首页 > 其他分享 >06.类-数组(array)和string

06.类-数组(array)和string

时间:2024-08-31 11:48:08浏览次数:12  
标签:06 string int 元素 数组 array include 标识符

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 用于对象数据成员的结构化绑定

若初始化表达式为类/结构体类型,则标识符列表中的名字绑定到类/结构体的非静态数据成员

  1.   数据成员必须为公有成员
    
  2.   标识符数量必须等于数据成员的数量
    
  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

相关文章

  • 一文说透 String 的 HashCode
    首先需要明确版本,不同版本的实现是不同的。JDK1.8以前底层的实现是char[]。publicinthashCode(){inth=hash;if(h==0&&value.length>0){charval[]=value;for(inti=0;i<value.length;i++){h=31*......
  • 最常用集合 - arraylist详解
    ArrayList介绍ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现。除该类未实现同步外,其余跟Vector大致相同。每个ArrayList都有一个容量(capacity),表示底层数组的实际大小,容器内存储元素的个数不能多于当前容量。当向容器......
  • 题解:CF915G Coprime Arrays
    题意我们称一个大小为\(n\)的数组\(a\)互质,当且仅当\(\gcd(a_1,a_2,\cdots,a_n)=1\)。给定\(n,k\),对于每个\(i\)\((1\lei\lek)\),你都需要确定这样的数组的个数——长度为\(n\)的互质数组\(a\),满足对每个\(j\)\((1\lej\len)\),都有\(1\lea_j\lei\)。分析......
  • 代码随想录算法训练营,8月30日 | 203.移除链表元素, 707.设计链表, 206.反转链表
    链表理论基础1.单链表:数据域和指针域(指向下一个结点的位置)组成,头结点,结尾为空指针;双链表:多了一个指向前一个结点的指针;循环链表:结尾指向头结点。2.链表在内存中的存储不是顺序的,跟数组不同,要找一个数据只能通过前一个数据来找,所有这就导致链表的查询比数组麻烦,但是插入删除数据......
  • [WPF]数据绑定时为何会出现StringFormat失效Nd
    在数据绑定过程中,我们经常会使用StringFormat对要显示的数据进行格式化,以便获得更为直观的展示效果,但在某些情况下格式化操作并未生效,例如Button的Content属性以及ToolTip属性绑定数据进行StringFormat时是无效的。首先回顾一下StringFormat的基本用法。StringFormat的用法Str......
  • [WPF]数据绑定时为何会出现StringFormat失效hC
    在数据绑定过程中,我们经常会使用StringFormat对要显示的数据进行格式化,以便获得更为直观的展示效果,但在某些情况下格式化操作并未生效,例如Button的Content属性以及ToolTip属性绑定数据进行StringFormat时是无效的。首先回顾一下StringFormat的基本用法。StringFormat的用法Str......
  • [WPF]数据绑定时为何会出现StringFormat失效2T
    在数据绑定过程中,我们经常会使用StringFormat对要显示的数据进行格式化,以便获得更为直观的展示效果,但在某些情况下格式化操作并未生效,例如Button的Content属性以及ToolTip属性绑定数据进行StringFormat时是无效的。首先回顾一下StringFormat的基本用法。StringFormat的用法Str......
  • [WPF]数据绑定时为何会出现StringFormat失效VPqCe7cCvg7iTH0g
    在数据绑定过程中,我们经常会使用StringFormat对要显示的数据进行格式化,以便获得更为直观的展示效果,但在某些情况下格式化操作并未生效,例如Button的Content属性以及ToolTip属性绑定数据进行StringFormat时是无效的。首先回顾一下StringFormat的基本用法。StringFormat的用法Str......
  • PowerShell Select-String:在字符串和文件中查找文本
    语法Select-String[-Culture<String>][-Pattern]<String[]>[-Path]<String[]>[-SimpleMatch][-CaseSensitive][-Quiet][-List][-NoEmphasis][-Include<String[]>][-Exclu......
  • [WPF]数据绑定时为何会出现StringFormat失效
    在数据绑定过程中,我们经常会使用StringFormat对要显示的数据进行格式化,以便获得更为直观的展示效果,但在某些情况下格式化操作并未生效,例如Button的Content属性以及ToolTip属性绑定数据进行StringFormat时是无效的。首先回顾一下StringFormat的基本用法。StringFormat的用法Str......