C++中有多下标数组。多下标数组常用于表示由行和列组成的表格。要表示表格中的元素,就要指定两个下标:习惯上第一个表示元素的行,第二个表示元素的列。
用两个下标表示特定的表格或数组称为双下标数组(double-subscripted array)。注意,多下标数组可以有多于两个的下标,C++编译器支持至少12个数组下标。图4.21演示了双下标数组a。数组包含三行四列,因此是3 x 4数组。一般来说,m行和n列的数组称为m x n数组。
数组a中的每个元素如图4.21所示,元素名字表示为a[i][j],i和j是数组名,i和j是惟一标识a中每个元素的下标。注意第一行元素名的第一个下标均为0,第四列的元素名的第二个下标均为3。
常见编程错误4. 11
把双下标数组元素a[x][y]误写成a[x,Y]。实际上,a[x,y]等于a[y],因为C++将包含返号运算符的表达式(x,y)求值为y(逗号分隔的表达式中最后一个项目)。多下标数组可以在声明中初始化,就像单下标数组一样。例如,双下标数组b[2][2]可以声明和初始化如下:
int b[2][2] = { { l, 2 }, { 3,4 } };
数值用花括号按行分组,因此1和2初始化b[0][0]和b[0][1],3和4初始化b[1][0]和b[1][1]。
如果指定行没有足够的初始化值,则该行的其余元素初始化为0。这样,下列声明:
int b[2][2] = { { 1 },{ 3,4 } };
初始化b[0][0]为1、b[0][1]为0、b[1][0)]为3、b[1][1]为4。
图4.22演示了声明中初始化双下标数组。程序声明三个数组,各有两行三列。array1的声明在两个子列表中提供六个初始化值。第一个子列表初始化数组第一行为1、2、3,第二个子列表初始化数组第二行为4、5、6。如果从array1初始化值列表中删除每个子列表的花括号,则编译器自动先初始化第一行元素,然后初始化第二行元素。
array2声明提供六个初始化值。初始化值先赋给第一行,再赋给第二行。任何没有显式初始化值的元素都自动初始化为0,因此array2[1][2]自动初始化为0。
// Fig. 4.22: fig04_22.cpp // Initializing multidimensional arrays #include < iostream.h> void printArray( int [][ 3 ] ); int main() { int arrayl[ 2 ][ 3 ] = { { 1, 2, 3 }, { 4, 5, 6 } }, array2[ 2][ 3] { 1, 2, 3, 4, 5 }, array3[ 2][ 3] ={ { 1, 2 }, { 4 } }; cout << "Values in arrayl by row are:" << endl; printArray( array1 ); cout << "Values in array2 by row are:" << endl; printArray( array2); cout << "Values in array3 by row are:" << endl; printArray( array3 ); return 0; } void printArray( int a[][ 3 ] ) { for (int i = 0; i < 2; i++ ) { for ( int j = 0; j < 3; j++ ) cout << a[ i ][ j ] << ' '; cout << endl; } }
图4.22初始化多维数组
array3的声明在两个子列表中提供3个初始化。第一行的子列表显式地将第一行的前两个元素初始化为1和2,第3个元素自动初始化为0。第二行的子列表显式地将第一个元素初始化为4,最后两个元素自动初始化为0。
程序调用函数printArray输出每个数组的元素。注意函数定义指定数组参数为int a[][3]。函数参数中收到单下标数组时,函数参数表中的数组括号是空的。多下标数组第一个下标的长度也不需要,但随后的所有下标长度都是必须的。编译器用这些长度确定多下标数组中元素在内存中的地址。不管下标数是多少,所有数组元素都是在内存中顺序存放。在双下标数组中,第一行后面的内存地址存放第二行。
在参数声明中提供下标使编译器能告诉函数如何找到数组中的元素。在双下标数组中,每行是一个单下标数组。要找到特定行中的元素,函数要知道每一行有多少元素,以便在访问数组时跳过适当数量的内存地址。这样,访问a[1][2]时,函数知道跳过内存中第一行的3个元素以访问第二行(行1),然后访问这一行的第3个元素(元素2)。
许多常见数组操作用for重复结构。例如,下列for结构(见图4.21)将数组a第三行的所有元素设置为o:
for(column=O;coulumn <4;column++) a[2][Column] = O;
我们指定第三行,因此知道第一个下标总是2 (0是第一行的下标,1是第二行的下标)。for循环只改变第二个下标(即列下标)。上述for结构等同于下列赋值语句:
a[2][0]=0;
a[2][1]=0;
a[2][2]=0;
a[2][3]=0;
下列嵌套for结构确定数组a中所有元素的总和:
total = 0; for ( row = O; row < 3; row++ ) for ( column = 0; column < 4; column++ ) total += a [ row ] [ column ] ;
for结构一次一行地求数组中所有元素的和。外层for结构首先设置row(即行下标)为0,使第一行的元素可以用内层for结构求和。然后外层for结构将row递增为1,使第二行的元素可以用内层for结构求和。然后外层for结构将mw递增为2,使第三行的元素可以用内层for结构求和。结束嵌套br结构之后,打印结果。
图4.23的程序对3 x 4数组studentCrades进行几个其他常见数组操作。每行数组表示一个学生,每列表示学生期末考试中4门成绩中的一门成绩。数组操作用4个函数进行。函数mimimum确定该学期所有学生考试成绩中的最低成绩。函数maximum确定该学期所有学生考试成绩中的最高成绩。
函数average确定每个学生该学期的平均成绩。函数printArray以整齐的表格形式输出双下标数组。
// Fig. 4.23: fig04_23.cpp // Double-subscripted array example #include <iostream.h>
#include <iomanip.h> const iht students = 3; // number of students const iht exams = 4; // number of exams int minimum( int [][ exams ], int, int ); int maximum(int [][ exams ], int, int }; float average( int [], int ); void printArray( int [][ exams ], int, int ); int main() I5 { int studentGrades[ students ][ exams ] = { { 77, 68, 86, 73 }, { 96, 87, 89, 78 }, { 70, 90, 86, 81 } }; cout << "The array is:\n"; printArray( studentGrades, students, exams ); cout << "\n\nLowest grade: " << minimum( studentGrades, students, exams ) << "\nHighest grade:" << maximum( studentGrades, students, exams ) << '\n'; for ( int person = 0; person < students; person++ } cout << "The average grade for student" << person << "is" << setprecision( 2 ) << average( studentGrades[ person ], exams ) << endl; return 0; // Find the minimum grade int minimum( int grades[][ exams ], int pupils, int tests ) { int lowGrade = 100; for ( int i = O; i < pupils; i++ ) for ( int j = 0; j < tests; j++ ) if ( grades[ i ][ j ] < lowGrade ) lowGrade = grades[ i ] [ j ]; return lowGrade; } // Find the maximum grade int maximum( int grades[][ exams ], iht pupils, iht tests ) { int highgrade = 0; for ( int i = 0; i < pupils; i++ ) for (int j = 0; j < tests; j++ ) if ( grades[ i ][ j ] > highgrade ) highgrade = grades[ i ][ j ]; return highgrade; } // Determine the average grade for a particular student float average(int setofGrades[],int tests) { int total = 0; for ( int i = 0; i < tests; i++ ) total += setofGrades[ i ]; return ( float ) total / tests; } // Print the array { I cout <<" [ 0 ] [ 1 ] [ 2 ] [ 3 ]"; for (int i = 0; i < pupils; i++ ) { cout << "\nstudentGrades[ "<< i << "] "; for(int j=0; j< tests;j++) cout << setiosflags( ios::left ) << setw( 5 ) << grades[ i ][ j ]; }
输出结果:
The array is:
[0] [1] [2] [3]
StudentGrades[ 0 ] 77 68 86 73
StudentGrades[ 1 ] 96 87 98 78
StudentGrades[ 2 ] 70 90 86 81
Lowest grade: 68
Highest grade: 96
The average grade for student 0 is 76.00
The average grade for student 1 is 87.50
The average grade for student 2 is 81.75
图 4.23 使用双下标数组举例
函数minimum、maximum和printArray取得三个参数——studentGrades数组(在每个函数中调用grades)、学生数(数组行)、考试门数(数组列)。每个函数用嵌套for结构对grades数组循环。
下列嵌套for结构来自函数mlmmum的定义:
for(i = 0;i < pupils;i++) for(j = O;j < tests;j++) if(grades[i][j] < lowGrade) lowGrade = grades[i][i];
外层for结构首先将i(行下标)设置为0,使第一行的元素可以和内层for结构体中的变量lowGrade比较。内层for结构比较lowGrade与4个成绩中的每一门成绩。如果成绩小于lowGrade,则lowGrade设置为该门成绩。然后外层for结构将行下标加到1,第二行的元素与变量lowGrade比较。接着外层for结行下标加到2,第三行的元素与变量lowGrade比较。嵌套for结构执行完成后,lowGrade包含双下标数组中的最小值。函数maximum的执行过程与函数minimum相似。
函数average取两个参数:一个单下标数组为某个学生的考试成绩,一个数字表示数组中有几个考试成绩。调用average时,第一个参数studentGrades[student]指定将双下标数组studentGrades的特定行传递给average。例如,参数studentGrad[1]表示双下标数组studentGrades第二行中存放的4个值(成绩的单下标数组)。双下标数组可以看作元素是单下标数组的数组。函数average计算数组元素的和,将总和除以考试成绩的个数,并返回一个浮点数结果。