技术交流QQ群:1027579432,欢迎你的加入!

1.Cpp中的数组

  • C++支持数组数据结构,它可以存储一个固定大小的相同类型的元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。数组的声明并不是声明一个个单独的变量,如a0,a1,a2,a3,a4...,a99,而是声明一个数组变量,比如as,然后使用as[0],as[1],as[2],...,as[99]来代表一个个单独的变量,数组的特定元素可以通过索引来访问。所数组都是由连续的内存位置组成,最低的地址对应第一个元素,最高的地址对应最后一个元素。

2.声明数组

  • 在C++在声明一个数组,需要指定元素的类型和元素的数量,如下所示:
    数据类型 数组名[元素数量];
  • 上面声明的格式是一维数组的声明,其中元素个数必须是一个大于0的整型常量,数据类型可以是任意有效的C++数据类型。如声明一个类型为double的包含10个元素的数组balance,声明语句是: double balance[10];

3.初始化数组

  • 在C++中,可以逐个初始化数组,也可以使用一个初始化语句,如下所示:
    double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
  • 大括号{ }之间的值的数目不能大于在数组声明时在方括号[ ]中指定的元素数目
  • 如果省略掉了数组的大小,数组的大小则为初始化时元素的个数。因此,如果是下面的格式,将创建一个数组,它与前一个实例中所创建的数组是完全相同的
    double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};
  • 为数组中某个元素赋值的实例,下面的语句把数组中第五个元素的值赋为666.6。所有的数组都是以0作为它们第一个元素的索引,也被称为基索引,数组的最后一个索引是数组的总大小减去1
    balance[4] = 666.6;

4.访问数组元素

  • 数组元素可以通过数组名称加索引进行访问。元素的索引是放在方括号内,跟在数组名称的后边。例如:
    double salary = balance[3];
  • 声明数组、初始化数组、访问数组元素实例如下:
    #include "iostream"
        #include "iomanip"
    
        using namespace std;
        using std::setw;   //  setw() 函数来格式化输出
    
        int main(){
            int a[10];   // 声明一个包含10个元素的整型数组
            // 初始化数组
            for (int i = 0; i < 10; i++)
                a[i] = i + 100;
            cout << "元素索引" << setw(13) << "元素值" << endl;
            // 输出数组中的每个元素
            for (int j = 0; j < 10; j++)
                cout << setw(7) << j << setw(13) << a[j] << endl;
            return 0;
        }

5.与数组有关的概念

与数组有关的概念.png
  • 5.1 ***数组
  • C++支持***数组。***数组声明的一般形式如下:
    数据类型名 数组名[size1][size2]...[sizeN];
  • 例如,下面的声明创建了一个三维整型数组:
    int tridim[5][10][4];
  • 二维数组
    • ***数组最简单的形式是二维数组。一个二维数组,在本质上,是一个一维数组的列表。声明一个x行y列的二维整型数组,形式如下:
      数据类型 数组名[x][y];
    • 一个二维数组可以被认为是一个带有x行和y列的表格。下面是一个二维数组,包含3行和4列:


      二维数组.png
    • 因此,数组中的每个元素是使用形式为a[i][j]的元素名称来标识的,其中a是数组名称,i和j 是唯一标识a中每个元素的下标。
    • 初始化二维数组
      • ***数组可以通过在括号内为每行指定值来进行初始化,下面是一个带有3行4列的数组。
        int a[3][4] = {
                {0, 1, 2, 3},   /*  初始化索引号为 0 的行 */
                {4, 5, 6, 7},   /*  初始化索引号为 1 的行 */
                {8, 9, 10, 11}, /*  初始化索引号为 2 的行 */
            };
      • 内部嵌套的括号是可选的,下面的初始化与上面是等同的:
        int a[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
    • 访问二维数组元素
      • 二维数组中的元素是通过使用下标(即数组的行索引和列索引)来访问的。例如:
        int val = a[2][3];
      • 二维数组如下:
        // 1.二维数组
            int aa[5][2] = {{0, 0}, {1, 2}, {2, 4}, {5, 7}, {9, 10}};
            for (int i = 0; i < 5; i++){
                for (int j = 0; j < 2; j++){
                    cout << "aa[" << i << "][" << j << "] = " << aa[i][j] << endl;
                }
            }
  • 5.2 指向数组的指针----数组指针
  • 数组名是一个指向数组中第一元素的常量指针(int const *p;),因此,double a[40];a是一个指向&a[0]的指针,即数组a的第一个元素的地址。因此,下面的程序片段p赋值给a的第一个元素的地址:
    double *p;
        double a[10];
        p = a;
  • 使用数组名作为常量指针是合法的,因此*(a+4)是一种访问a[4]数据的合法方式。一旦把第一个元素的地址存储在p中,就可以使用*p,*(p+1),*(p+2)等来访问数组的元素。
    // 2.指向数组的指针:数组指针
        double b[5] = {12.4, 3.1, 5.6, 0.8, 5.4};
        double *p;  // 一个指向double型的指针,可以存储一个double类型变量的地址
        p = b;
        cout << "使用指针的数组值 " << endl;
        for (int i = 0; i < 5; i++)
            cout << "*(p + " << i << ") = " << *(p + i) << endl;
        cout << "使用b作为地址的数组值 " << endl;
        for (int i = 0; i < 5; i++)
            cout << "*(b + " << i << ") = " << *(b + i) << endl;
  • C++中,将char*或char[]传给cout进行输出,结果会是整个字符串,如果想要获得字符串的地址(第一个字符的地址),可以使用方法:强制转化为其他指针(非char),可以是void*, float*,int*,double*等。使用&s[0]不能输出s[0]的地址,因为&s[0]将返回char*,对于char*,cout会将其作为字符串来处理,向下查找字符并输出直到字符结束*。
    // C++中,将char*或char[]传递给cout进行输出,结果会是整个字符串。如果想要获得字符串的地址,强制转化为其他指针(非char*)
        char var[MAX] = {'a', 'b', 'c'};
        char *ptr;
        // 指针中的数组地址
        ptr = var;
        for (int i = 0; i < 3; i++){
            cout << "var[" << i << "]的地址是 = " << (int *)ptr << endl;
            cout << "var[" << i << "] = " << *ptr << endl;
            ptr++;  // 移动到下一个位置
        }
  • 5.3 C++中传递数组给函数
  • C++中可以通过指定不带索引的数组名来传递一个指向数组的指针
  • C++传数组给一个函数,数组类型自动转换为指针类型,因此传的实际是地址
  • 如果想在函数中传递一个一维数组作为参数,必须用下面三种方式来声明函数形式参数,这三种声明方式的结果是一样的,因为每种方式都会告诉编译器将要接收一个整型指针。同样的,也可以传递一个***数组作为形式参数。
    • 方式1(形式参数是一个指针))
      void func1(int *param){
              ...
          }
    • 方式2(形式参数是一个已定义大小的数组))
      void func1(int params[10]){
              ...
          }
    • 方式3(形式参数是一个未定义大小的数组)
      void func1(int params[]){
              ...
          }
  • 实例如下:
    // 3.C++中把数组传递给函数(方法1)
        int bb[5] = {1000, 2, 3, 17, 50};
        double avg, avg1;
        // 传递一个指向数组的指针作为参数
        avg = getAverage(bb, 5);
        cout << "平均值: " << avg << endl;
        /*-----------------------方法2-----------------------*/
        int bbb[5] = {1000, 2, 3, 17, 50};
        int *ptr1 = bbb;
        // 分别计算数组元素个数,以及整型指针的字节数
        size_t bbb_size = sizeof(bbb) / sizeof(int);
        size_t ptr1_size = sizeof(ptr1);
        cout << "bbb size = " << bbb_size << endl;
        cout << "ptr1 size = " << ptr1_size << endl;
        avg1 = getAverage1(bbb, 5);
        cout << "平均值: " << avg1 << endl;
    
        // 方法1(下面的例子中把数组作为参数,同时还传递了另一个参数)
        double getAverage(int arr[], int size){
            int i, sum = 0;
            double avg;
            cout << "sizeof(arr) = " << sizeof(arr) << endl;
            for (i = 0; i < size; i++)
                sum += arr[i];
            avg = double(sum) / size;
            return avg;
        }
    
        // 方法2
        double getAverage1(int *arr, int size){
            int i, sum = 0;
            double avg;
            cout << "sizeof(arr) = " << sizeof(arr) << endl;
            for (i = 0; i < size; i++)
                sum += arr[i];
            avg = double(sum) / size;
            return avg;
        }
  • 5.4 从函数返回数组
  • C++不允许返回一个完整的数组作为函数的参数。但是,可以通过指定不带索引的数组名来返回一个指向数组的指针。C++不支持在函数外返回局部变量的地址,除非定义局部变量为static变量。如果想要从函数返回一个一维数组,必须声明一个返回指针的函数(指针函数),如下:
    int * func(){
            ...
        }
  • 实例如下:
    // 要生成和返回随机数的函数
        int * getRandom(){
            static int r[10];  // C++不支持在函数外返回局部变量的地址,除非定义局部变量为static变量
            // 设置随机数种子
            srand((unsigned)time(NULL));
            for (int i = 0; i < 10; i++){
                r[i] = rand();
                cout << "r[" << i << "] = " << r[i] << endl;
            }
            return r;
        }
        // 4.从函数返回数组----指针函数
            int *p1; 
            p1 = getRandom();
            for (int i = 0; i < 10; i++)
                cout << "*( p1 + " << i << ") = " << *(p1 + i) << endl;

6.数组中的细节知识

  • 直接初始化字符数组char是特殊的,这种初始化需要一个null作为结尾的。如下:
    char a1[] = {'p', 'y', 't', 'h', 'o', 'n'};  // 初始化,没有 null
        char a2[] = {'p', 'y', 't', 'h', 'o', 'n', '\0'};   // 初始化,明确有 null
        char a3[] = "python";  // null 终止符自动添加
        const char a4[6] = "python";  // 报错,没有 null 的位置
  • 数组的大小是固定的,不能额外增加元素,当想定义不固定大小的字符时,使用vector!
    vector<int> vec;  // 创建向量用于存储整型数据
        int m;
        // 显示vec初始大小
        cout << "vector size = " << vec.size() << endl;
        // 向向量vec追加5个整数值
        for(int m = 0; m < 5; m++)
            vec.push_back(m);
        // 显示追加后vec的大小
        cout << "追加后的vector size = " << vec.size() << endl;
  • 在C++中,setw(int n)用来控制输出间隔,(n-1个空格),setw()默认填充的内容是空格,可以使用setfill()配合使用设置其他字符填充。
cout << setfill('*') << setw(5) << 'a' << endl;
  • 静态与动态数组
    静态 int array[100];  定义了数组 array,并未对数组进行初始化
            int array[100] = {1, 2};  定义并初始化了数组 array
    
        动态 int * array = new int[100];  分配了长度为 100 的数组 array
            delete [] array;
    
        动态 int * array = new int[100]{1, 2};  为长度为100的数组array初始化前两个元素
            delete [] array;
  • 数组初始化时可以用聚合方法,但是赋值时候不可以用聚合方法。举例如下:
    int array[] = {5,10,20,40};   // 合法
    
        int array[];
        int main()
        {
        array[] = {5,10,20,40}; // 不合法
        return 0;
        }
  • 数组在使用时可以是一个含有变量的表达式,但是,在数组声明时必须用常量表达式。例如:
    // 合法
        const int a=19;
        long b[a];
    
        // 合法
        const int a=19;
        long b[a+5];
    
        // 不合法
        int a=19;
        long b[a+5];
  • 声明一个任意长度的数组,可以用显式的类型转换,例如:
    int a=19;
        int b[(const int)a];
  • 也可以定义一个常量来声明,例如:
    int a=19;
        const int a1=a;
        int b[a1];
  • Vector(向量): C++中的一种数据结构,确切的说是一个类。它相当于一个动态的数组,当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间的目的。
    • 用法:
      • 1.文件包含:
        • 首先在程序开头处加上 #include<vector> 以包含所需要的类文件vector;还有一定要加上 using namespace std;
      • 2.变量声明:
        • 2.1例: 声明一个 int 向量以替代一维的数组: vector <int> a; (等于声明了一个 int 数组 a[],大小没有指定,可以动态的向里面添加删除)。
        • 2.2例: 用vector代替二维数组.其实只要声明一个一维数组向量即可,而一个数组的名字其实代表的是它的首地址,所以只要声明一个地址的向量即可,即: vector <int *> a。同理想用向量代替三维数组也是一样,vector <int**>a;
      • 3.具体的用法以及函数调用:
        • 3.1 得到向量中的元素和数组一样,例如:
          vector <int *> a
              int b = 5;
              a.push_back(b);//该函数下面有详解
              cout << a[0];       //输出结果为5
        • 使用数组给向量赋值:
          vector<int> v( a, a+sizeof(a)/sizeof(a[0]) );
        • 或者:
          int a[]={1,2,3,4,5,6,7,8,9};
              typedef vector<int> vec_int;
              vec_int vecArray(a,a+9);