6. 类-数组(array)和string
6.1 数组
数组是一组连续的内存位置,它们都具有相同的类型。为了指代数组中的特定位置或元素,我们指定数组的名称和特定元素在数组中的位置编号。数组名称遵循与其他变量名相同的约定。
下标必须是整数或整数表达式,带下标的数组名是一个左值,它可以在赋值的左边使用,就像非数组变量名一样。通过调用函数可以知道数组的长度,例如c.size()。包含下标的括号实际上是一个操作符,它与用于调用函数的括号具有相同的优先级。
6.2 声明array
数组在内存中占据空间,使用声明的形式来指定数组所需的元素类型和元素个数。数组和向量都是类模板。使用数组必须使用头文件<array>
例如:
array<type,arraySize> arrayName{值1,值2,...};
6.2.1 C++17关于array的新特性
C++17引入了一种新特性,对类模板的参数进行推导,例如:
std::array a1{1,4,6};
std::array a2{'w','b','o'};
6.3 使用数组的例子
6.3.1 声明数组并使用循环初始化数组的元素
size_t是一种数据相关的无符号整数类型,它被设计得足够大以便能够内存中任意对象的大小。size_t由来: 在C++中,设计 size_t 就是为了适应多个平台的 。size_t的引入增强了程序在不同平台上的可移植性。在需要通过数组下标来访问数组时,通常建议将下标定义size_t类型,因为一般来说在进行下标访问时,下标都是正的。这种类型对于任何表示数组大小或数组下标的变量都是推荐的。头文件为<cstddef>。此头文件包含在各种其他的头文件中,如果程序出现错误,说size_t未定义,只需要在程序中加上#include<cstddef>
#include <iostream>
#include <iomanip>
#include <array>
using namespace std;
int main(){
array<int,5> n;
for(size_t i{0};i<n.size();++i){
n[i]=0;
}
cout<<"element"<<setw(10)<<"value"<<endl;
for(size_t j{0};j<n.size();++j){
cout<<setw(7)<<j<<setw(10)<<n[j]<<endl;
}
}
上诉代码将数组初始化并将数组内元素打印出来。
6.3.2 在声明里通过初始化列表初始化数组
如果初始化列表内的元素个数小于数组长度,剩余的元素会被初始化为0。如果大于数组长度,则是错误。
6.3.3 用常量设定数组的大小并通过计算设置数组元素
第10行使用const限定符声明一个常量变量数组Size,其值为5。常量变量(Constant variables)也被称为命名常量(named constants)或只读变量(read-only variables)。一个常量变量在声明时必须初始化,此后不能修改。尝试将arraySize初始化后进行修改,会出现错误。
6.3.4 数组元素的和
#include <iostream>
#include <array>
using namespace std;
int main() {
const size_t arraySize{4};
array<int,arraySize> a{10,20,30,40};
int total{0};
for(size_t i{0};i<a.size();i++){
total+=a[i];
}
cout<<"total of array elements is: "<<total<<endl;
}
上诉代码计算数组元素的和。
6.3.8 Static Local arrays and Automatic Local arrays
程序在首次遇到静态局部数组的声明时,对其进行初始化。如果你没有显式地初始化一个静态数组,那么在创建该数组时,编译器会将该数组的每个元素初始化为零。C + +对其他局部变量不执行这样的默认初始化。
局部变量有时被称为自动变量,因为当函数执行完毕时,局部变量会被自动销毁。
#include <iostream>
#include <array>
using namespace std;
void staticArrayInit();
void automaticArrayInit();
const size_t arraySize{3};
int main() {
cout<<"first call to each function:\n";
staticArrayInit();
automaticArrayInit();
cout<<"\n\nSecond call to each function:\n";
staticArrayInit();
automaticArrayInit();
cout<<endl;
}
void staticArrayInit(){
static array<int,arraySize> array1;
cout<<"\nValues on entering staticArrayInit:\n";
for(size_t i{0};i<array1.size();++i){
cout<<"array1["<<i<<"]="<<array1[i]<<" ";
}
cout<<"\nValues on exiting staticArrayInit:\n";
for(size_t j{0};j<array1.size();++j){
cout<<"array1["<<j<<"]="<<(array1[j]+=5)<<" ";
}
}
void automaticArrayInit(){
array<int, arraySize> array2{1, 2, 3};
cout << "\n\nValues on entering automaticArrayInit:\n";
for (size_t i{0}; i < array2.size(); ++i) {
cout << "array2[" << i << "] = " << array2[i] << " ";
}
cout << "\nValues on exiting automaticArrayInit:\n";
for (size_t j{0}; j < array2.size(); ++j) {
cout << "array2[" << j << "] = " << (array2[j] += 5) << " ";
}
}
如前所述,static数组的值,在函数执行一次后,值不会销毁。
6.4 基于范围的for循环(range based for statement)
如前所述,对数组中的所有元素进行处理是很常见的。基于范围的for循环允许您在不使用counter的情况下执行此操作,从而避免了"跳出"数组的可能性,也无需您执行自己的边界检查。
#include <iostream>
#include <array>
using namespace std;
int main() {
array<int,5> items{1,2,3,4,5};
cout<<"items before modification: ";
for(int item:items){
cout<<item<<" ";
}
for(int& itemRef: items){
itemRef*=2;
}
cout<<"\nitems after modification: ";
for(int item:items){
cout<<item<<" ";
}
cout<<endl;
}
for(int item:items){
cout<<item<<" ";
}
与如下的代码实现的功能一样:
基于范围的for语句简化了通过数组进行迭代的代码。上诉第二个代码块的for循环,可以讲是:对于每一次迭代,将items的下一个元素的值赋给int类型的变量item,然后执行循环。因此,对于每次迭代,item都代表items的一个值(不是下标)。在基于范围的for的函数头中,在冒号(:)的左边声明一个所谓的范围变量,并在右边指定一个数组的名称。You can use the range-based for statement with most of the C++ Standard Library’s prebuilt data structures (commonly called containers).
当通过数组的代码在循环时不需要访问元素的下标时,可以使用基于范围的for语句代替counter控制的for语句。l例如,计算数组中所有元素的和,就不需要数组下标。但是,如果一个程序由于某种原因必须使用下标,而不是简单地通过数组(例如,在每个数组元素值的旁边打印一个下标数字,如本章前面的例子)循环,则应该使用counter进行for语句控制。
6.6 数组的排序和查找
#include <iostream>
#include <iomanip>
#include <array>
#include <string>
#include <algorithm>
using namespace std;
int main() {
const size_t arraySize{5};
array<string,arraySize> colors{"red","orange","yellow","blue","green"};
cout<<"unsorted array\n";
for(string color:colors){
cout<<color<<" ";
}
sort(colors.begin(),colors.end());
cout<<"sorted array:\n";
for(string item:colors){
cout<<item<<" ";
}
bool found{binary_search(colors.begin(),colors.end(),"indigo")};
cout<<"\n\n\"indigo\" "<<(found? "was":"was not")
<<"found in colors"<<endl;
found= binary_search(colors.begin(),colors.end(),"cyan");
cout<<"\"cyan\" "<<(found?"was":"was not")
<<"found in colors"<<endl;
}
使用binary_search函数,首先必须对一组元素进行升值排序。函数的前两个实参表明寻找的范围,最后一个实参表示要寻找的元素。返回一个bool值指出是否寻找到此元素。
6.7 多维数组
二维数组的声明:
array<array<int,3>,3> a;
#include <iostream>
#include <array>
using namespace std;
const size_t rows{2};
const size_t columns{3};
void printArray(const array<array<int,columns>,rows>&);
int main(){
array<array<int,columns>,rows> array1{1,2,3,4,5,6};
array<array<int,columns>,rows> array2{1,2,3,4,};
cout<<"values in array1 by row are: "<<endl;
printArray(array1);
cout<<"\nvalues in array2 by row are: "<<endl;
printArray(array2);
}
void printArray(const array<array<int,columns>,rows>& a){
for(auto const& row:a){
for(auto const& element:row){
cout<<element<<' ';
}
cout<<endl;
}
}
为了处理二维数组的元素,我们使用了一个嵌套循环,其中外循环通过行进行迭代,内循环通过给定行的列进行迭代。如上诉代码21-22行所示。
上诉的嵌套循环代码可以替换为如下的形式:
上诉代码可以求得二维数组所有元素的总和。
二维数组的声明如下所示:
array<array<int,columns>,rows> array1{1,2,3,4,5,6};
columns表示二位数组的列数,rows代表二位数组的行数。
对二维数组使用size函数,返回的是数组的行数。例如:a.size()返回数值2。
6.8 C++字符串类(string)
C++中使用string类处理字符串。操作string对象中的字符串时,有时会用到"index".
创建string对象:
1.用无参构造函数创建一个空字串
string newString;
2.由一个字符串常量或字符串数组创建string对象
string message{"aloha world"};//
char charArr[]={'h','e','l','l','o'};
string message1{charArr};//
string的成员函数可以参见std::basic_string - cppreference.com
6.9 C++17 结构化绑定(structured binding)
结构化绑定声明是一个声明语句,意味着声明了一些标识符并对标识符做了初始化,在C++17标准中引入。
将指定的一些名字绑定到初始化器的子对象或者元素上。
cv-auto &/&& [标识符列表]= 表达式;
cv-auto &/&& [标识符列表] {表达式};
cv-auto &/&& [标识符列表] (表达式);
cv-auto:可能由const/volatile修饰的auto关键字
&/&& :左值引用或者右值引用
标识符列表:逗号分隔的标识符
6.9.1 用于原生数组的结构化绑定声明
若初始化表达式为数组类型,则标识符列表中的名字绑定到数组元素。
1.标识符数量必须等于数组元素数量
2.标识符类型与数组元素类型一致
int main(){
int priArr[] {42,21,7};
auto [a1,a2,a3]=priArr;//a1是priArr[0]的拷贝,a2,a3类推
const auto [b1,b2,b3] (priArr);//b1是priArr[0]的只读拷贝,b2,b3类推
auto &[c1,c2,c3] {priArr};//c1是priArr[0]的引用,c2,c3类推
c3=14;//priArr[2]的值变为14
return 0;
}
6.9.2 用于std::array的结构化绑定声明
若初始化表达式为数组类型,则标识符列表中的名字绑定到数组元素。
1.标识符数量必须等于array中的元素数量
2.标识符类型与array中的元素类型一致
int main(){
std::array stdArr={'a','b','c'};//C++17
auto [d1,d2,d3]{stdArr};
return 0;
}
6.9.3 用于对象数据成员的结构化绑定
若初始化表达式为类/结构体类型,则标识符列表中的名字绑定到类/结构体的非静态数据成员上
-
数据成员必须为公有成员
-
标识符数量必须等于数据成员的数量
-
标识符类型与数据成员类型一致
class C { // 可以改用 struct C,然后去掉下面的public属性说明
public:
int i { 420 }; // 就地初始化
char ca[ 3 ] { 'O', 'K', '!' };
};
int main() {
C c;
auto [a1, a2] {c}; // a1是int类型,a2是char[]类型
std::cout << "c.i:" << a1 << " c.ca:" << b2 << std::endl;
}
auto后跟&,则标识符是数据成员的引用
auto前可放置const,表明标识符是只读的
int main() {
C c; // c.i: 420; c.ca: 'O','K','!'
auto [a1, a2] {c}; // a1是c.i的拷贝,a2是char[]类型
auto& [b1, b2] {c}; // b1是int&类型,是c.i的引用,
// b2是char(&)[3]类型(数组的引用),是c.ca的引用
a1 = 100;
std::cout << "c.i:" << c.i << std::endl; // 输出420,改a1不影响c.i
b1 = 200;
std::cout << "c.i:" << c.i << std::endl; // 输出200,通过b1修改了c.i
}
标签:06,string,int,元素,数组,array,include,标识符
From: https://www.cnblogs.com/yyyylllll/p/18390066