⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 04章 数组.txt

📁 C++大学教程txt版中文版 C++大学教程txt版中文版
💻 TXT
📖 第 1 页 / 共 5 页
字号:
arrayl[ 0 ] = 5 array1[ 1 ] = 5 array1[ 2 ] = S

Values on entering automaticArrayInit:
array2[ 0 ] = 1 array2[ 1 ] = 2 array2[ 2 ] = 3
Values on exitimg automaticArraylmit:
arrayl[ 0 ] = 6 array2[ 1 ] = 7 array2[ 2 ] = 8

second call to each function:

Values on entering staticArrayImit:
arrayl[ 0 ] = 5 arrayl[ 1 ] = 5 arrayl[ 2 ] = 5
Values on exiting staticArrayInit:
arrayl[ 0 ] = 10 arrayl[ 1 ] = 10 arrayl[ 2 ] = 10

Values on entering automaticArrayInit:
array2[ 0 ] = 1 array[ 1 ] = 2 array2[ 2 ] = 3

Values on exiting automaticArrayInit:
array2[ 0 ] = 6 array2[ 1 ] = 7 array2[ 2 ] = 8


                                 图4.13  比较static数组初始化和自动数组初始化

    常见编程错误4.9
    假设每次调用函数时函数局部static数组的元素初始化为0将导致程序中的逻辑错误。

4.5  将数组传递给函
    要将数组参数传递给函数,需指定不带方括号的数组名。例如,如果数组hourlyTemperatures声明如下:
    int hourlyTemperatures[24];
则下列函数调用语句:
    modifyArray(hourlyTemperatutes,24);
将数组hourlyTemperatures及其长度传递给函数modifyArray。将数组传递给函数时,通常也将其长度传递给函数,使函数能处理数组中特定的元素个数(否则要在被调用函数中建立这些信息,甚至要把数组长度放在全局变量中)。第8章介绍Array类时,将把数组长度设计在用户自定义类型中,每个Array对象生成时都“知道”自己的长度。这样,将Array对象传递给函数时,就不用把数组长度作为参数一起传递。
    C++使用模拟的按引用调用,自动将数组传递绐函数,被调用函数可以修改调用者原数组中的元素值。数组名的值为数组中第一个元素的地址。由于传递数组的开始地址,因此被调用函数知道数组的准确存放位置。因此,被调用函数在函数体中修改数组元素时.实际上是修改原内存地址中的数组元素。

    性能提示4.4
    模拟按引用调用传递数组时才能有性能上的意义。如果数组按值传递,则是传递每个元素的副本。对于经常传递的大数组,这是很费时间的,而且存放数组副本要占用很大空间。
    软件工程视点4.2
    也可以按值传递数组(用第6章介绍的简单方法),但很少使用。

    尽管模拟按引用调用传递整个数组,但各个数组元素和简单变量一样是按值传递。这种简单的单个数据称为标量(scalar 或scalar quanity)。要将数组元素传递给函数,用数组元素的下标名作为函数调用中的参数。第5章将介绍标量(即各个变量和数组元素)的模拟按引用调用。
    要让函数通过函数调用接收数组,函数的参数表应指定接收数组。例如,函数modifyArray的函数苜部可能如下所示:
    void modifyArray(int b[],int arraySize)
表示modifyArray要在参数b中接收整型数组并在参数arraySize中接收数组元素个数。数组方括号中的数组长度不是必需的,如果包括,则编译器将其忽略。由于模拟按引用调用传递数组,因此被调用函数使用数组名b时,实际上引用调用者的实际数组(上例中为数组hourlyTemperatures)。第5章介绍表示函数接收数组的其他符号,这些符号基于数组与指针之间的密切关系。
   注意modlfyArray函数原型的表示方法:
    void modifyArray(int[],int);
这个原型也可以改写成:
    void modifyArray( int anyArrayName[],int( anyVariableName )
但第3章曾介绍过,C++编译器忽略函数原型中的变量名。

    编程技巧4.3
    有些程序员在函数原型中包括变量名,使程序更清晰,编译器将忽略这个名称。
    记住,函数原型告诉编译器参数个数和参数类型(按参数出现的顺序)。
    图4.14的程序演示了传递整个数组与传递数组元素之间的差别。程序首先打印整型数组a的五个元素,然后将a及其长度传递给函数modifyArray,其中将a数组中的元素乘以2,然后在main中重新打印a。从输出可以看出,实际由modifyAnay修改a的元素。现在程序打印a[3]的值并将其传递给函数modifyElement。函数modifyElement将参数乘以2。然后打印新值。注意在main中重新打印a[3]时,它没有修改,因为各个数组元素是按值调用传递。
1 // Fig. 4.14: fig0414.cpp
2 // Passing arrays and individual array elements to functions
3 #include <iostream.h>
4 #include <iomanip.h>
5
6 void modifyArray( int [], int );  // appears strange
7 void modifyElement( int );
8
9  int main()
10 {
11    const int arraySize = 5;
12    iht i, a[ arraySize ] = { 0, 1, 2, 3, 4 };
13
14    cout << "Effects of passing entire array call-by-reference:"
15        << "\n\nThe values of the original array are:\n";
16
17  for( i=0;i< arraySize; i++ )
18      cout(<< setw( 3 ) << a[ i ];
19
20    cout << endl;
21
22    // array a passed call-by-reference
23    modifyArray( a, arraySize );
24
25    cout << "The values of the modified array are:\n";
26
27    for ( i = 0; i < arraySize; i++ )
28      cout << setw( 3 ) << a[ i ] ;
29
30    cout << "\n\n\n"
31        << "Effects of passing array element call-by-value:"
32    <<"\n\nThe value of a[3] is "<< a[3] <<'\n';
33
34     modifyElement( a[ 3 ] );
35
36     cout << "The value of a[ 3 ] is "<< a[ 3 ] << endl;
37
38     return 0;
39 }
4O
41 void modifyArray( int b[ ], int sizeofArray )
42 {
43     for ( int j = 0; j < sizeofArray; j++ )
44        b[ j ] *= 2;
45 }
46
47 void modifyElement( int e )
48 {
49     cout << "Value in modifyElement is"
50        <<(e *= 2 ) << endl;
51 }

输出结果:
Effects of passing entire array call-by-Value:

The values of the original array are:
     0 1 2 3 4
The values of the modified array are:
     0 2 4 6 8

Effects of passing array element call-by-value:

The value of a[3] is 6
Value in modifyElement is 12
The value of a[3] is 6

                              图4.14  向函数传递数组和数组元素

    有时程序中的函数不能修改数组元素。由于总是模拟按引用调用传递数组.因此数组中数值的修改很难控制。C++提供类型限定符const,可以防止修改函数中的数组值。数组参数前面加上const限定符时,数组元素成为函数体中的常量,要在函数体中修改数组元素会造成语法错误。这样,程序员就可以纠正程序,使其不修改数组元素。
    图4.15演示了const限定符。函数tryToModifyArray定义参数const int b[],指定数组b为常量,不能修改。函数想修改数组元素会造成语法错误“Canot modify const object”。const限定符将在第7章再次介绍。

1 // Fig. 4.15: fig04_lS.cpp
2 // Demonstrating the const type qualifier
3 #include <iostream.h>
4
5 void tryToModifyArray( const int [] );
6
7 int main()
8 {
9     int a[] = {10,20,30};
10
11    tryToModifyArray( a );
12    cout << a[ 0 ] << ' ' << a[ 1 ] << ' ' << a[ 2 ] << '\n';
13    return 0;
14 }
15
16 void tryToModifyArray( const int b[] )
17 {
18    b[ 0 ] /= 2;   // error
19    b[ 1 ] /= 2;   // error
20    b[ 2 ] /= 2;   // error
21 }

输出结果:
Compiling FIG04 15.CPP:
Error FIG04_iS.CPP 18: Canot modify a const object
Error FIG04_iS.CPP 19: Canot modify a const object
Error FIG04 15.CPP 20: Canot modify a const object
Warning FIG04_15,CPP 21: Parameter 'b' is never used

                                    图4.15  演示const限定符
    
    常见编程错误4.10
    忘记数组按引用传递以至于修改数组可能造成逻辑错误。
    软件工程视点4.3    .
    const限定符可以用于函数定义中的数组参数,防止函数体中修改原数组,这是最低权限原则的另一个例子。函数不能提供修改数姐的功能,除非确实有必要。

4.6  排序数组
    排序(sort)数组(即将数据排成特定顺序,如升序或降序)是一个重要的计算应用。银行按账号排序所有支票,使每个月末可以准备各个银行报表。电话公司按姓氏排序账号清单并在同一姓氏中按名字排序,以便于找到电话号码。几乎每个公司都要排序一些数据,有时要排序大量数据。
排序数据是个复杂问题,是计算机科学中大量研究的课题。本章介绍最简单的排序机制,在本章练习和第15章中,我们要介绍更复杂的机制以达到更高的性能。

    性能提示4.5
    有时最简单的算法性能太差,但易于编写、测试和调试。更复杂的算法在需要实现最高性能时才会用到。
    图4.16的程序排列10个元素数组a的值,按升序排列。我们使用冒泡排序(bubble sort sinkingsort)方法,较少的数值慢慢从下往上“冒”,就像水中的气泡一样,而较大的值则慢慢往下沉。这个方法在数组中多次操作,每一次都比较一对相邻元素。如果某一对为升序(或数值相等),则将数值保持不变。如果某一对为降序,则将数值交换。

1 // Fig. 4.16:fig04 16.cpp
2 // This program sorts an array's values into
3 // ascending order
4 #include <iostream.h>
5 #include <iomanip.h>
6
7 int main{)
8 {
9   const int arraySize = 10;
10  int a[ arraySize ] = { 2, 6, 4, 8, 10, 12, 89, 68, 45, 37 };
11  int i, hold;
12
13  cout << "Data items in original order\n";
14
15  for ( i = 0; i < arraySize; i++ )
16     cout << setw( 4 ) << a[i ] ;
17
18  for (int pass = 0; pass < arraySize - 1; pass++ ) // passes
19
20     for ( i = 0; i < arraySize - 1; i++ )     // one pass
21
22        if ( a[i ] > a[i + 1 ] ) {     // one comparison
23          hold  a[i ];              // one swap
24          a[i ] = a[i + 1 ];
25          a[i + 1 ] = hold;
26        }
27
28   cout << "\nData items in ascending order\n";
29
30   for ( i = 0; i < arraySize; i++ )
31     cout << setw( 4 ) << a[ i ];
32
33   cout << endl;
34   return 0;
35 }

输出结果:
  Data  items  in  Oriqinal  order
    2    6    4    8    10    12    89    68    45    37
    Data  items  in  ascendinq  order
    2    4    6    8    10    12    37    45    68    89

                                       图4.16用冒泡法排序数组

 程序首先比较a[0]与a[1],然后比较a[1]与a[2],接着是a[2]与a[3],一直到比较a[8]与a[9]。尽管有10个元素,但只进行9次比较。由于连续进行比较,因此一次即可能将大值向下移动多位,但小值只能向上移动一位。第1遍,即可把最大的值移到数组底部,变为a[9]。第2遍,即可将第2大的值移到a[8]第9遍,将第9大的值移到a[1]。最小值即为a[0],因此,只进行9次比较即可排序10个元素的数组。
    排序是用嵌套for循环完成的。如果需要交换,则用三条赋值语句完成:
    hold = a[ i ];;
    a[i] = a[ i+1 ];
    a[ i+1 ] = hold;
其中附加的变量hold临时保存要交换的两个值之一。只有两个赋值语句是无法进行交换的:
    a[ i ] = a [ i+1 ];
    a[ i+l] =a[ i];
例如,如果a[i]为7而a[i+1]为5.则第一条赋值语句之后,两个值均为5,数值7丢失,因此要先用变量ho1d临时保存要交换的两个值之一。
    冒泡排序的主要优点是易于编程。但冒泡排序的速度很慢,这在排序大数组时更明显。练习中要开发更有效的冒泡排序程序,介绍一些比冒泡排序更有效的方法。高级课题中将介绍更深入的排序与查找问题。

4.7  实例研究:用数组计算平均值、中数和模
    下面要举一个更大的例子。计算机常用于编译和分析调查结果,图4.17的程序用数组response
初始化调查的99个答复(用常量变量response表示),每个答复是1到9的数值。程序计算99
个值的平均值、中数和模。

1 // Fig. 4.17: fig04_lT.cpp
2 // This program introduces the topic of survey data analysis.
3 // It computes the mean, median, and mode of the data.
4 #include <iostream.~
5 #include <iomanip.h>
6
7 void mean( const int[],int );
8 void median( int []
9 voidmode(int[],int[],int);
l0 void bubbleSort( int[ ] , int );
11 voidprintArray(constint[],int);
12
13 int main()
14 {
15     const int responseSize = 99;
16     intfrequency[10] ={ 0 },
17         response[ responseSize ] =
i8           {6,7,8,9,8,7,8,9,8,9,
19             7,8,9,5,9,8,7,8,7,8,
20             6,7,8,9,3,9,8,7,8,7,
21             7,8,9,8,9,8,9,7,8,9,
22             6,7,8,7,8,7,9,8,9,2,
23             7,8,9,8,9,8,9,7,5,3,
24             5,6,7,2,5,3,9,4,6,4,
25             7,8,9,6,8,7,8,9,7,8,
26             7,4,4,2,5,3,8,7,5,6,
27             4,5,6,1,6,5,7,8,7};
28
29    mean( response, responseSize );
30    median( response, responseSize );
31    mode( frequency, response, responseSize );
32
33    return O;
34}
35
36 void mean( const int answer[], int arraySize )
37 {
38     int total = 0;
39
4O    cout << "********\n Mean\n********\n";
41
42    for ( int j = 0; j < arraySize; j++ )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -