从零开始学Visual C++
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.6 数组

数组(Array)是用于处理同种类型数据的集合,比如有50个人的成绩,可以存放到大小为50的整型数组中,便于进行排序、求平均值、最大最小值等操作。数组在定义时需要指定大小,以便分配固定大小的存储空间,在实际开发中,常使用动态大小的链式数据结构替代数组。

1.6.1 什么是数组

数组是内存上连续排列的一种数据结构,数组的起始地址是第一个元素所在的地址,通过下标索引可访问某个元素,索引从0开始编号,最后一个元素的索引值为数组长度减1,若索引大于等于数组长度,会引发程序崩溃。

声明数组时需明确指定数组大小,若要使用变量指定数组大小,可用new运算符动态生成一个数组,在使用完数组后用delete运算符手动释放该数组。

1.6.2 一维数组

一维数组可看做一组连续排列的数据集合,数组占用内存大小等于数组长度乘以数组元素的大小,使用下标索引访问每个元素,如a[i]代表第i+1个元素。定义数组时可进行初始化,若不对每个元素赋值,系统将分配一个随机值,用{}初始化数组可不指定大小。

【实例1-21】定义一个一维数组,根据元素值进行升序排序后,获取数组的最大值、最小值、平均值。

        #include <iostream>
        using namespace std;
        int main()
        {
            int score[]={78,90,88,100,87};                 //定义并初始化一维数组
            int count=sizeof(score)/sizeof(int);           //计算数组大小
            for(int i=0;i<count-1;i++)                     //数组按照从小到大的顺序排序
            {
                for(int j=i;j<count;j++)
                {
                    if(score[i]>score[j])                  //若第i元素大于后面的元素,交换值
                    {
                        int temp=score[i];                 //将第i个元素的值暂时保存到temp中
                        score[i]=score[j];                 //将第j个元素的值赋给第i个元素
                        score[j]=temp;                     //将temp保存的值赋给第j个元素
                    }
                }
            }
            int sum=0;                                     //总和
            cout<<"排序后:";
            for(int k=0;k<count;k++)                       //遍历数组,输出排序后的数组
            {
                sum+=score[k];                             //数据累加
                cout<<score[k]<<" ";
            }
            cout<<endl<<endl;
            cout<<"最大值:"<<score[count-1]<<endl;        //最大值
            cout<<"最小值:"<<score[0]<<endl;              //最小值
            cout<<"平均值:"<<(double)sum/count<<endl;     //平均值
            return 0;
        }

编译运行,结果如图1-18所示。定义数组时直接使用{}赋初值,这样无须在[]中输入数组的大小,自动根据{}中元素的数目决定数组的大小。sizeof(score)得到整个数组占用的内存大小,sizeof(int)得到一个int元素占用的大小,相除得到数组元素数目。

图1-18 一维数组

两个for循环用于对数组排序,外层for循环第1次循环得到最小值,用第1个元素的值与其后的所有元素比较,若第1个元素的值大于其后的某个元素,将较小的元素和第1个元素交换值,这样第1个元素的值始终是较小的,所有元素都比较结束后,第1个元素的值就是最小值。第2次循环用第2个元素的值与其后的所有元素比较,得到次小值,依此类推。

排序后将每个元素的值累加,得到所有元素的总和,除以元素数目得到平均值。由于排序方式为升序,第1个元素为最小值,最后一个元素为最大值。

1.6.3 二维数组

二维数组可看做一个n行m列的矩阵,使用方法类似于一维数组。通过下标访问每个元素,如a[i][j]代表第i行j列的元素(索引从0开始编号)。

二维数组定义时可进行初始化,如int a[][2]={{1,2},{3,4}};内层的{1,2}为第一行的初始值,数组a的行数为内层{}的数目,可不指定大小,但必须指定数组a的列数,内层{}中元素的数目不能大于列数,若小于列数,剩余未赋值的元素默认为0。

【实例1-22】定义二维数组并初始化,获取行数和列数,输出所有元素的值。

        #include <iostream>
        using namespace std;
        int main()
        {
            int a[2][3]={{1,3,4},{7,5,6}};                    //定义二维数组并初始化
            int row=sizeof(a)/sizeof(a[0]);                   //行数
            int column=sizeof(a[0])/sizeof(int);              //列数
            cout<<"a行数:"<<row<<endl;
            cout<<"a列数:"<<column<<endl;
            for(int i=0;i<row;i++)                            //输出所有元素
            {
                for(int j=0;j<column;j++){
                    cout<<a[i][j]<<" ";
                }
                cout<<endl;                                   //换行
            }
            cout<<endl;
            return 0;
        }

编译运行,结果如图1-19所示。初始化时一个内层{}表示一行数据,sizeof(a)得到整个二维数组占用的内存大小,sizeof(a[0])得到一行元素占用的内存大小,sizeof(int)得到一个int元素的大小,用数组总大小除以一行大小得到行数,用一行大小除以每个元素大小得到列数。

图1-19 二维数组

外层的for循环遍历每一行,内层的for循环遍历当前行的每一列,两个for循环输出所有元素,当输出一行元素后,输出换行符,另起一行显示下一行元素。

1.6.4 动态数组

声明数组时必须指定固定的大小值,但有时候在运行前并不知道元素的总数目,需要在程序运行时确定元素数目,可使用new运算符在程序运行时动态生成一定大小的数组。

一般类型的变量都有作用域,程序运行时在栈(stack)中创建,当超出变量作用域后被自动释放。使用new运算符动态创建的变量在堆(heap)中创建,不会自动释放,必须使用delete运算符手动释放。若使用new动态创建后忘记用delete释放,会造成内存泄漏,这也是C++被认为不安全的原因之一。

【实例1-23】用new运算符动态创建一个数组,对元素赋值并输出后,用delete运算符释放该数组。

        #include <iostream>
        using namespace std;
        int main()
        {
            int cnt=10;
            int* a=new int[cnt];                      //动态创建数组,数组大小为变量cnt
            for(int i=0;i<10;i++)                     //数组赋值
            {
                a[i]=i*10-i;
                cout<<a[i]<<" ";
            }
            delete [] a;                              //释放动态创建的数组
            cout<<endl;
            return 0;
        }

用new运算符动态创建一个int数组,大小为变量cnt,返回一个int指针,指向刚分配的数组的首地址。数组名实际上等于数组第一个元素的地址,即a等同于&a[0],所以数组变量和指针变量性质是相同的。

使用完数组后,要用delete手动释放,如delete a; a为要释放的变量的地址,若a指向的是一个数组,需要使用[]表明要释放的是数组,如delete [] a;否则只释放第一个元素。

1.6.5 数组排序

在一维数组中使用了一种排序方法,C++函数库自带一个排序函数qsort,用于实现对数组的快速排序,函数格式如下:

        void qsort(void *buf, size_t num, size_t size, int (*compare)(const void *, const
    void *))

参数:

❑ buf:数组首地址(数组名即可)。

❑ num:数组元素数目。

❑ size:每个元素的字节大小。

❑ compare:比较函数名,指定了函数原型。

size_t是unsigned int类型的重定义,格式如下:

        typedef unsigned int size_t;

typedef将一种类型重命名为另一种名称,便于根据类型即可知道变量的作用,实际上还是一种数据类型,Windows API有很多陌生的数据类型,都是使用typedef进行基本类型的重定义得到的。

int (*compare)(const void *, const void *)表示一个符合特定函数原型的指针,即传入的函数名的原型必须与该原型一致,qsort函数根据该函数的返回值决定是否交换两个参数。

【实例1-24】使用qsort函数对数组进行排序,输出排序后的元素。

        #include <iostream>
        using namespace std;
        int compare(const void* a,const void* b)  //排序比较函数,a和b为比较的两个数据的指针
        {
            int n1=*((int*)a);                    //指针a对应的值
            int n2=*((int*)b);                    //指针b对应的值
            if(n1<n2)                             //若参数1的值小于参数2的值,返回-1
                return -1;
            else if(n1==n2)                       //若相等,返回0
                return 0;
            else                                  //若大于,返回1
                return 1;
        }
        int main()
        {
            int a[5]={46,43,90,10,40};                             //定义并初始化数组
            qsort(a,sizeof(a)/sizeof(int),sizeof(int),compare);    //快速排序
            for(int i=0;i<sizeof(a)/sizeof(int);i++)               //显示排序后的数组元素
            {
                cout<<a[i]<<" ";
            }
            cout<<endl;
            return 0;
        }

传入compare函数的指针为void类型,需要转换为实际的int类型,利用*获取指针指向的值。函数compare的原型必须与qsort函数中的定义保持一致,对传入的两个值进行判断,compare函数可决定在何种情况下返回何值。

若compare函数返回正值,qsort函数会交换两个参数的值,如当参数1大于参数2时,返回正值,qsort函数交换参数1和参数2的值,实现升序排序。