文章目录
1. 定义数字
通常,当需要用到数字时,我们会使用原始的数据类型,如 int、short、long、float 和 double 等等。
#include <iostream>
#include <iomanip> // 包含 iomanip 以便格式化输出
using namespace std;
int main() {
// 数字定义与赋值
short s = 10;
int i = 1000;
long l = 1000000;
float f = 230.47f;
double d = 30949.374;
// 数字输出
cout << left << setw(10) << "short s:" << s << endl;
cout << left << setw(10) << "int i:" << i << endl;
cout << left << setw(10) << "long l:" << l << endl;
cout << left << setw(10) << "float f:" << fixed << setprecision(2) << f << endl;
cout << left << setw(10) << "double d:" << fixed << setprecision(1) << d << endl;
return 0;
}
输出结果:
short s: 10
int i: 1000
long l: 1000000
float f: 230.47
double d: 30949.4
2. 数学运算
在 C++ 中,除了可以创建各种函数,还包含了各种有用的函数供您使用。这些函数写在标准 C 和 C++ 库中,叫做内置函数。您可以在程序中引用这些函数。
C++ 内置了丰富的数学函数,可对各种数字进行运算。为了利用这些函数,需要引用数学头文件 <cmath>。
序号 | 函数 & 描述 |
---|---|
1 | double cos(double); 该函数返回弧度角(double 型)的余弦。 |
2 | double sin(double); 该函数返回弧度角(double 型)的正弦。 |
3 | double tan(double); 该函数返回弧度角(double 型)的正切。 |
4 | double log(double); 该函数返回参数的自然对数。 |
5 | double pow(double, double); 假设第一个参数为 x,第二个参数为 y,则该函数返回 x 的 y 次方。 |
6 | double hypot(double, double); 该函数返回两个参数的平方总和的平方根,也就是说,参数为一个直角三角形的两个直角边,函数会返回斜边的长度。 |
7 | double sqrt(double); 该函数返回参数的平方根。 |
8 | int abs(int); 该函数返回整数的绝对值。 |
9 | double fabs(double); 该函数返回任意一个浮点数的绝对值。 |
10 | double floor(double); 该函数返回一个小于或等于传入参数的最大整数。 |
代码示例:
#include <iostream>
#include <cmath>
using namespace std;
int main() {
// 数组定义
int nums[] = {2, 4, 6, 8}; // 定义一个整型数组
double angles[] = {30.0, 45.0, 60.0}; // 定义一个浮点型数组,表示角度
// 数组数学运算
cout << "平方 nums[2]: " << pow(nums[2], 2) << endl; // 计算 nums 数组第三个元素的平方
cout << "正弦角度 angles[1]: " << sin(angles[1] * M_PI / 180) << endl; // 计算 angles 数组第二个元素的正弦值
cout << "平方根 nums[3]: " << sqrt(nums[3]) << endl; // 计算 nums 数组第四个元素的平方根
cout << "对数 nums[1]: " << log(nums[1]) << endl; // 计算 nums 数组第二个元素的自然对数
cout << "余弦角度 angles[0]: " << cos(angles[0] * M_PI / 180) << endl; // 计算 angles 数组第一个元素的余弦值
return 0;
}
-
数组定义:
int nums[] = {2, 4, 6, 8};
:定义了一个包含四个整型元素的数组nums
。double angles[] = {30.0, 45.0, 60.0};
:定义了一个包含三个浮点型元素的数组angles
,这些浮点数代表角度。
-
数组元素的数学运算:
pow(nums[2], 2)
:计算nums
数组第三个元素的平方,即6的平方。sin(angles[1] * M_PI / 180)
:将角度从度数转换为弧度后,计算angles
数组第二个元素的正弦值,即45度的正弦值。sqrt(nums[3])
:计算nums
数组第四个元素的平方根,即8的平方根。log(nums[1])
:计算nums
数组第二个元素的自然对数,即4的自然对数。cos(angles[0] * M_PI / 180)
:将角度从度数转换为弧度后,计算angles
数组第一个元素的余弦值,即30度的余弦值。
3. 随机数
在许多情况下,需要生成随机数。关于随机数生成器,有两个相关的函数。一个是 rand(),该函数只返回一个伪随机数。生成随机数之前必须先调用 srand() 函数。
下面是一个关于生成随机数的简单实例。实例中使用了 time() 函数来获取系统时间的秒数,通过调用 rand() 函数来生成随机数:
代码示例:
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int main ()
{
const int SIZE = 10;
int randomNumbers[SIZE]; // 定义一个数组来存储随机数
// 设置种子
srand(static_cast<unsigned int>(time(NULL)));
// 生成并存储 10 个随机数
for (int i = 0; i < SIZE; i++) {
randomNumbers[i] = rand(); // 生成实际的随机数并存储到数组中
}
// 输出生成的随机数
for (int i = 0; i < SIZE; i++) {
cout << "随机数[" << i << "] : " << randomNumbers[i] << endl;
}
return 0;
}
const int SIZE = 10;
:定义了一个常量SIZE
表示数组的大小。int randomNumbers[SIZE];
:定义了一个数组randomNumbers
来存储生成的随机数。- 第一段
for
循环生成10个随机数并存储在数组中。 - 第二段
for
循环遍历数组,输出所有生成的随机数。
4. 数组
C++ 支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 numbers[0]、numbers[1]、...、numbers[99] 来代表一个个单独的变量。数组中的特定元素可以通过索引访问。
所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。
声明数组
在 C++ 中要声明一个数组,需要指定元素的类型和元素的数量,如下所示:
type arrayName [ arraySize ];
这叫做一维数组。arraySize 必须是一个大于零的整数常量,type 可以是任意有效的 C++ 数据类型。例如,要声明一个类型为 double 的包含 10 个元素的数组 balance,声明语句如下:
double balance[10];
现在 balance 是一个可用的数组,可以容纳 10 个类型为 double 的数字。
初始化数组
在 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};
您将创建一个数组,它与前一个实例中所创建的数组是完全相同的。下面是一个为数组中某个元素赋值的实例:
balance[4] = 50.0;
上述的语句把数组中第五个元素的值赋为 50.0。所有的数组都是以 0 作为它们第一个元素的索引,也被称为基索引,数组的最后一个索引是数组的总大小减去 1。
5. 访问数组元素
数组元素可以通过数组名称加索引进行访问。元素的索引是放在方括号内,跟在数组名称的后边。例如:
double salary = balance[9];
上面的语句将把数组中第 10 个元素的值赋给 salary 变量。下面的实例使用了上述的三个概念,即,声明数组、数组赋值、访问数组:
代码示例:
#include <iostream>
#include <iomanip> // 包含 iomanip 以使用 setw
using namespace std;
int main() {
int n[5][3]; // n 是一个 5x3 的二维数组
// 初始化数组元素
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 3; j++) {
n[i][j] = (i + 1) * (j + 1); // 乘法表的部分示例
}
}
// 输出表头
cout << setw(5) << "Row" << setw(10) << "Col1" << setw(10) << "Col2" << setw(10) << "Col3" << endl;
// 输出数组中的每个元素的值
for (int i = 0; i < 5; i++) {
cout << setw(5) << i + 1; // 输出行号
for (int j = 0; j < 3; j++) {
cout << setw(10) << n[i][j]; // 按格式输出数组元素
}
cout << endl; // 换行
}
return 0;
}
-
数组定义与初始化:
int n[5][3];
定义了一个 5x3 的二维数组。- 嵌套的
for
循环用于初始化数组元素,每个元素的值是(i + 1) * (j + 1)
,这类似于乘法表的部分内容。
-
格式化输出:
setw
函数用于设置输出的字段宽度,以确保输出对齐。- 在输出表头时,使用
setw(5)
对齐行号,使用setw(10)
对齐列标题。 - 在输出数组内容时,使用
setw(10)
格式化每个数组元素的输出,使其在列中对齐。
6. 数组类型
概念 | 描述 |
---|---|
多维数组 | C++ 支持多维数组。多维数组最简单的形式是二维数组。 |
指向数组的指针 | 您可以通过指定不带索引的数组名称来生成一个指向数组中第一个元素的指针。 |
传递数组给函数 | 您可以通过指定不带索引的数组名称来给函数传递一个指向数组的指针。 |
从函数返回数组 | C++ 允许从函数返回数组。 |
7. 多维数组
C++ 支持多维数组。多维数组声明的一般形式如下:
type name[size1][size2]...[sizeN];
下面的声明创建了一个三维 5 . 10 . 4 整型数组:
int threedim[5][10][4];
二维数组
多维数组最简单的形式是二维数组。一个二维数组,在本质上,是一个一维数组的列表。声明一个 x 行 y 列的二维整型数组,形式如下:
type arrayName [ x ][ y ];
其中,type 可以是任意有效的 C++ 数据类型,arrayName 是一个有效的 C++ 标识符。
一个二维数组可以被认为是一个带有 x 行和 y 列的表格。下面是一个二维数组,包含 3 行和 4 列:
因此,数组中的每个元素是使用形式为 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];
上面的语句将获取数组中第 3 行第 4 个元素。您可以通过上面的示意图来进行验证。让我们来看看下面的程序,我们将使用嵌套循环来处理二维数组:
代码示例:
#include <iostream>
using namespace std;
int main() {
// 定义一个 5 行 2 列的数组,并初始化
int a[5][2] = {
{0,0}, {1,2}, {2,4}, {3,6}, {4,8}};
// 输出数组中每个元素的值,并计算每行元素的和
for (int i = 0; i < 5; i++) {
int rowSum = 0; // 定义变量计算每行的和
for (int j = 0; j < 2; j++) {
cout << "a[" << i << "][" << j << "]: " << a[i][j] << endl;
rowSum += a[i][j]; // 计算当前行的元素和
}
cout << "Sum of row " << i << " is: " << rowSum << endl; // 输出当前行的和
cout << "----------" << endl;
}
return 0;
}
输出结果:
a[0][0]: 0
a[0][1]: 0
Sum of row 0 is: 0
----------
a[1][0]: 1
a[1][1]: 2
Sum of row 1 is: 3
----------
a[2][0]: 2
a[2][1]: 4
Sum of row 2 is: 6
----------
a[3][0]: 3
a[3][1]: 6
Sum of row 3 is: 9
----------
a[4][0]: 4
a[4][1]: 8
Sum of row 4 is: 12
----------
-
数组定义与初始化:
int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6}, {4,8}};
:定义并初始化了一个5行2列的二维数组a
。每个元素对表示一个简单的线性关系,如{0,0}, {1,2}, {2,4}
等。
-
计算并输出每行的和:
- 内层循环遍历数组的每一列,输出每个元素的值,并同时累加每行的元素。
- 在内层循环结束后,输出当前行的元素和(
rowSum
),并打印分隔线----------
来区分不同的行。
-
添加的增强内容:
- 计算并输出每行元素的和,增加了代码的功能性,使其不仅仅是输出元素值,还增加了对数组内容的处理。
- 每行输出的分隔线使得输出结果更清晰,便于阅读和理解。
8. 指向数组的指针
数组名是指向数组中第一个元素的常量指针。
double runoobAarray[50];
runoobAarray 是一个指向 &runoobAarray[0] 的指针,即数组 runoobAarray 的第一个元素的地址。因此,下面的程序片段把 p 赋值为 runoobAarray 的第一个元素的地址:
double *p;
double runoobAarray[10];
p = runoobAarray;
使用数组名作为常量指针是合法的。因此,*(runoobAarray + 4) 是一种访问 runoobAarray[4] 数据的合法方式。
一旦把第一个元素的地址存储在 p 中,您就可以使用 *p、*(p+1)、*(p+2) 等来访问数组元素。
代码示例:
#include <iostream>
using namespace std;
int main() {
// 带有 5 个元素的双精度浮点型数组
double runoobArray[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
p = runoobArray; // 将指针 p 指向数组的起始地址
// 使用指针遍历并输出数组中每个元素的值
cout << "使用指针遍历并输出数组的值:" << endl;
for (int i = 0; i < 5; i++) {
cout << "*(p + " << i << ") : ";
cout << *(p + i) << endl;
}
cout << "\n使用数组名作为地址遍历并输出数组的值:" << endl;
for (int i = 0; i < 5; i++) {
cout << "*(runoobArray + " << i << ") : ";
cout << *(runoobArray + i) << endl;
}
// 使用指针修改数组中的元素
cout << "\n使用指针修改数组的值:" << endl;
for (int i = 0; i < 5; i++) {
*(p + i) *= 2; // 将每个元素的值加倍
cout << "新值 *(p + " << i << ") : ";
cout << *(p + i) << endl;
}
return 0;
}
使用指针遍历并输出数组的值:
*(p + 0) : 1000
*(p + 1) : 2
*(p + 2) : 3.4
*(p + 3) : 17
*(p + 4) : 50使用数组名作为地址遍历并输出数组的值:
*(runoobArray + 0) : 1000
*(runoobArray + 1) : 2
*(runoobArray + 2) : 3.4
*(runoobArray + 3) : 17
*(runoobArray + 4) : 50使用指针修改数组的值:
新值 *(p + 0) : 2000
新值 *(p + 1) : 4
新值 *(p + 2) : 6.8
新值 *(p + 3) : 34
新值 *(p + 4) : 100
-
定义与初始化:
double runoobArray[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
定义了一个包含5个双精度浮点数的数组,并初始化这些元素。double *p;
声明了一个指向双精度浮点数的指针变量p
。
-
使用指针访问数组:
p = runoobArray;
将指针p
指向数组runoobArray
的起始地址。*(p + i)
通过指针访问数组元素。这里展示了如何通过指针偏移(p + i
)来访问数组中第i
个元素的值。
-
使用数组名作为地址:
*(runoobArray + i)
直接使用数组名runoobArray
作为指针,结合偏移量i
来访问数组元素。这进一步说明了数组名本质上是指向数组起始地址的指针。
-
使用指针修改数组元素:
*(p + i) *= 2;
通过指针访问并修改数组元素的值,使得每个元素的值加倍。修改后的数组内容在随后被输出。
9. 传递数组给函数
可以通过指定不带索引的数组名来传递一个指向数组的指针。C++ 传数组给一个函数,数组类型自动转换为指针类型,因而传的实际是地址。
如果想要在函数中传递一个一维数组作为参数,必须以下面三种方式来声明函数形式参数,这三种声明方式的结果是一样的,因为每种方式都会告诉编译器将要接收一个整型指针。同样地也可以传递一个多维数组作为形式参数。
方式 1
形式参数是一个指针:
void myFunction(int *param)
{
.
.
.
}
方式 2
形式参数是一个已定义大小的数组:
void myFunction(int param[10])
{
.
.
.
}
方式 3
形式参数是一个未定义大小的数组:
void myFunction(int param[])
{
.
.
.
}
代码示例:
下面这个函数,它把数组作为参数,同时还传递了另一个参数,根据所传的参数,会返回数组中各元素的平均值:
double getAverage(int arr[], int size)
{
int i, sum = 0;
double avg;
for (i = 0; i < size; ++i)
{
sum += arr[i];
}
avg = double(sum) / size;
return avg;
}
现在调用上面的函数
#include <iostream>
using namespace std;
// 函数声明
double getAverage(int arr[], int size);
int main ()
{
// 带有 5 个元素的整型数组
int balance[5] = {1000, 2, 3, 17, 50};
double avg;
// 传递一个指向数组的指针作为参数
avg = getAverage( balance, 5 ) ;
// 输出返回值
cout << "平均值是:" << avg << endl;
return 0;
}
//平均值是: 214.4
就函数而言,数组的长度是无关紧要的,因为 C++ 不会对形式参数执行边界检查。
10. 从函数返回数组
C++ 不允许返回一个完整的数组作为函数的参数。但是可以通过指定不带索引的数组名来返回一个指向数组的指针。
如果想要从函数返回一个一维数组,必须声明一个返回指针的函数,如下:
int * myFunction() {
//. . .
}
代码示例:
int* myFunction()
{
int myArray[3] = {1, 2, 3};
return myArray;
}
注意:不能简单地返回指向局部数组的指针,因为当函数结束时,局部数组将被销毁,指向它的指针将变得无效。
C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。
为了避免以上情况,你可以使用静态数组或者动态分配数组。
使用静态数组需要在函数内部创建一个静态数组,并将其地址返回,例如:
int* myFunction()
{
static int myArray[3] = {1, 2, 3};
return myArray;
}
代码通过使用静态数组返回随机数列表,同时演示了如何通过指针来遍历和访问数组元素。
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
// 生成并返回包含随机数的数组的函数
int* getRandom() {
static int r[10]; // 静态数组,保证函数返回后数组依然存在
// 设置随机数种子
srand(static_cast<unsigned>(time(nullptr)));
// 生成随机数并存储在数组中
for (int i = 0; i < 10; ++i) {
r[i] = rand() % 100; // 生成100以内的随机数
cout << "Generated r[" << i << "] = " << r[i] << endl;
}
return r; // 返回数组的指针
}
int main() {
// 调用 getRandom 函数并获取返回的数组指针
int* p = getRandom();
cout << "\n使用指针遍历并输出数组的值:" << endl;
// 使用指针遍历并输出数组中的值
for (int i = 0; i < 10; ++i) {
cout << "*(p + " << i << ") = " << *(p + i) << endl;
}
return 0;
}
-
静态数组的使用:
- 在函数
getRandom
中,使用了静态数组r[10]
。静态数组在函数调用结束后仍然存在,因此可以安全地返回其指针。 - 这样做是为了避免返回局部变量的地址,该地址在函数退出后会被释放,从而导致未定义行为。
- 在函数
-
设置随机数种子:
- 使用
srand(static_cast<unsigned>(time(nullptr)));
为随机数生成器设置种子,确保每次运行程序时都会生成不同的随机数序列。 - 使用
rand() % 100
限制生成的随机数在0到99之间,增加了代码的实用性。
- 使用
-
随机数生成和输出:
- 在
getRandom
函数中,随机数被生成并存储到数组中,同时输出每个生成的随机数,这有助于在调试时了解数组的内容。
- 在
-
使用指针遍历数组:
- 在
main
函数中,通过指针p
遍历数组,并输出每个数组元素的值。这里展示了指针和数组的紧密关系,即数组名可以作为指针来使用。
- 在
输出结果:
Generated r[0] = 42
Generated r[1] = 17
Generated r[2] = 78
Generated r[3] = 96
Generated r[4] = 53
Generated r[5] = 29
Generated r[6] = 88
Generated r[7] = 14
Generated r[8] = 91
Generated r[9] = 35
使用指针遍历并输出数组的值:
*(p + 0) = 42
*(p + 1) = 17
*(p + 2) = 78
*(p + 3) = 96
*(p + 4) = 53
*(p + 5) = 29
*(p + 6) = 88
*(p + 7) = 14
*(p + 8) = 91
*(p + 9) = 35