数组与函数详解
一、数组
1. 一维数组
(1) 定义方式
一维数组是存储相同类型元素的线性集合,定义时需要指定数据类型和数组长度。
定义方式 | 示例 | 说明 |
---|---|---|
数据类型 数组名[数组长度]; |
int arr1[5]; |
定义长度为5的整型数组,未初始化 |
数据类型 数组名[数组长度] = {值1, 值2, ...}; |
int arr2[5] = {1,2,3,4,5}; |
定义并初始化(全部元素) |
数据类型 数组名[] = {值1, 值2, ...}; |
int arr3[] = {1,2,3}; |
定义并初始化,数组长度自动推断 |
特点:
- 数组元素在内存中连续存储
- 数组索引从0开始
- 数组长度必须是常量表达式
// 正确示例
const int SIZE = 5;
int arr[SIZE] = {10, 20, 30, 40, 50};
// 错误示例:长度不能是变量
int n = 5;
int wrong_arr[n]; // 编译错误
(2) 数组名的意义
数组名代表数组的首地址,是一个常量指针(不能修改指向)。
int arr[5] = {1, 2, 3, 4, 5};
cout << arr << endl; // 输出数组首地址
cout << &arr[0] << endl; // 输出第一个元素地址(与上面相同)
cout << sizeof(arr) << endl; // 输出整个数组大小(5*4=20字节)
(3) 元素逆置案例
将数组元素顺序颠倒的实现:
#include <iostream>
using namespace std;
int main() {
int arr[] = {1, 2, 3, 4, 5};
int length = sizeof(arr) / sizeof(arr[0]); // 计算数组长度
// 逆置算法:首尾交换
for (int start = 0, end = length - 1; start < end; start++, end--) {
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
}
// 输出结果:5 4 3 2 1
for (int i = 0; i < length; i++) {
cout << arr[i] << " ";
}
return 0;
}
(4) 一维数组冒泡排序⭐⭐⭐
冒泡排序是一种简单直观的排序算法:
#include <iostream>
using namespace std;
int main() {
int arr[] = {5, 3, 1, 4, 2};
int length = sizeof(arr) / sizeof(arr[0]);
// 冒泡排序(升序)
for (int i = 0; i < length - 1; i++) { // 外层循环:排序轮数
for (int j = 0; j < length - 1 - i; j++) { // 内层循环:每轮比较次数
if (arr[j] > arr[j+1]) { // 前一个比后一个大,交换
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
// 输出排序结果:1 2 3 4 5
for (int i = 0; i < length; i++) {
cout << arr[i] << " ";
}
return 0;
}
2. 二维数组
(1) 定义方式
二维数组可看作"数组的数组",常用于表示表格数据。
定义方式 | 示例 | 说明 |
---|---|---|
数据类型 数组名[行数][列数]; |
int arr1[2][3]; |
定义2行3列的二维数组,未初始化 |
数据类型 数组名[行数][列数] = {{值1,值2,...}, {...}}; |
int arr2[2][3] = {{1,2,3},{4,5,6}}; |
初始化所有元素(推荐) |
数据类型 数组名[行数][列数] = {值1,值2,...}; |
int arr3[2][3] = {1,2,3,4,5,6}; |
按顺序初始化(自动填充) |
数据类型 数组名[][列数] = {值1,值2,...}; |
int arr4[][3] = {1,2,3,4,5,6}; |
行数自动推断(列数必须指定) |
内存布局:
行0: [1][2][3]
行1: [4][5][6]
(2) 数组名的意义
二维数组名代表整个二维数组的首地址,是一个指向一维数组的指针。
int arr[2][3] = {{1,2,3},{4,5,6}};
cout << arr << endl; // 二维数组首地址
cout << arr[0] << endl; // 第一行首地址
cout << arr[1] << endl; // 第二行首地址
cout << &arr[0][0] << endl; // 第一个元素地址
(3) 考试成绩统计案例
统计3名学生4门课程的成绩:
#include <iostream>
#include <iomanip> // 用于格式化输出
using namespace std;
int main() {
const int STUDENTS = 3;
const int COURSES = 4;
int scores[STUDENTS][COURSES] = {
{85, 90, 78, 92},
{76, 88, 95, 80},
{92, 85, 90, 88}
};
// 打印表头
cout << "学号\t语文\t数学\t英语\t综合\t总分\t平均分" << endl;
// 计算每个学生的总分和平均分
for (int i = 0; i < STUDENTS; i++) {
int total = 0;
cout << i+1 << "\t";
// 输出各科成绩并计算总分
for (int j = 0; j < COURSES; j++) {
cout << scores[i][j] << "\t";
total += scores[i][j];
}
// 计算并输出总分和平均分
double average = static_cast<double>(total) / COURSES;
cout << total << "\t" << fixed << setprecision(1) << average << endl;
}
return 0;
}
输出结果:
学号 语文 数学 英语 综合 总分 平均分
1 85 90 78 92 345 86.2
2 76 88 95 80 339 84.8
3 92 85 90 88 355 88.8
二、函数
1. 函数定义与调用
函数是完成特定功能的代码块,提高代码复用性。
基本结构:
返回值类型 函数名(参数列表) {
// 函数体
return 返回值; // void函数可省略return
}
示例:
#include <iostream>
using namespace std;
// 函数定义
int add(int a, int b) {
return a + b;
}
int main() {
// 函数调用
int result = add(3, 4);
cout << "3+4=" << result << endl; // 输出:7
return 0;
}
2. 参数传递方式
传递方式 | 特点 | 示例 | 是否影响实参 |
---|---|---|---|
值传递 | 复制参数值 | void func(int a) {...} |
否 |
地址传递 | 传递内存地址(指针) | void func(int *p) {...} |
是 |
引用传递 | 创建变量的别名(推荐) | void func(int &r) {...} |
是 |
对比示例:
#include <iostream>
using namespace std;
// 值传递(不影响实参)
void changeValue(int a) {
a = 100;
}
// 地址传递(影响实参)
void changeByPointer(int *p) {
*p = 200;
}
// 引用传递(影响实参)
void changeByReference(int &r) {
r = 300;
}
int main() {
int num = 10;
changeValue(num);
cout << num << endl; // 输出:10
changeByPointer(&num);
cout << num << endl; // 输出:200
changeByReference(num);
cout << num << endl; // 输出:300
return 0;
}
3. 函数常见样式
函数样式 | 示例 | 说明 |
---|---|---|
无参无返回值 | void sayHello() {...} |
执行操作,不返回结果 |
有参无返回值 | void printSum(int a, int b) |
接收参数,执行操作 |
无参有返回值 | int getRandom() {...} |
生成并返回数据 |
有参有返回值 | int max(int a, int b) {...} |
接收参数,计算并返回结果 |
4. 函数声明
函数声明告诉编译器函数的存在,定义可以放在后面或其他文件。
#include <iostream>
using namespace std;
// 函数声明(可以多次)
int multiply(int a, int b);
int main() {
cout << multiply(5, 6) << endl; // 输出:30
return 0;
}
// 函数定义(只能一次)
int multiply(int a, int b) {
return a * b;
}
5. 函数的分文件编写⭐⭐⭐
将函数声明放在头文件(.h),定义放在源文件(.cpp),提高代码组织性。
项目结构:
project/
├── main.cpp
├── math_utils.h // 头文件
└── math_utils.cpp // 源文件
math_utils.h:
#pragma once // 防止头文件重复包含
// 函数声明
int add(int a, int b);
int subtract(int a, int b);
math_utils.cpp:
#include "math_utils.h"
// 函数定义
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
main.cpp:
#include <iostream>
#include "math_utils.h" // 包含自定义头文件
using namespace std;
int main() {
cout << "10 + 5 = " << add(10, 5) << endl;
cout << "10 - 5 = " << subtract(10, 5) << endl;
return 0;
}
6. 综合函数知识点案例
实现数组处理工具集:
array_utils.h:
#pragma once
// 打印数组
void printArray(int arr[], int size);
// 数组求和
int arraySum(int arr[], int size);
// 查找最大值
int findMax(int arr[], int size);
array_utils.cpp:
#include <iostream>
#include "array_utils.h"
using namespace std;
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
int arraySum(int arr[], int size) {
int sum = 0;
for (int i = 0; i < size; i++) {
sum += arr[i];
}
return sum;
}
int findMax(int arr[], int size) {
int max = arr[0];
for (int i = 1; i < size; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
main.cpp:
#include <iostream>
#include "array_utils.h"
using namespace std;
int main() {
int numbers[] = {12, 45, 23, 67, 34, 89};
int size = sizeof(numbers) / sizeof(numbers[0]);
cout << "原始数组: ";
printArray(numbers, size);
cout << "数组总和: " << arraySum(numbers, size) << endl;
cout << "最大值: " << findMax(numbers, size) << endl;
return 0;
}
三、数组与函数的结合应用
数组作为函数参数时,实际传递的是数组首地址,函数内部可以修改原始数组。
#include <iostream>
using namespace std;
// 修改数组元素
void doubleElements(int arr[], int size) {
for (int i = 0; i < size; i++) {
arr[i] *= 2; // 修改原始数组
}
}
// 打印数组
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
int main() {
int nums[] = {1, 2, 3, 4, 5};
int size = sizeof(nums) / sizeof(nums[0]);
cout << "原始数组: ";
printArray(nums, size); // 1 2 3 4 5
doubleElements(nums, size);
cout << "加倍后数组: ";
printArray(nums, size); // 2 4 6 8 10
return 0;
}
总结
知识点 | 要点 |
---|---|
一维数组 | 连续存储、索引从0开始、长度必须常量、数组名是首地址 |
二维数组 | 行优先存储、可看作一维数组的数组、初始化需指定列数 |
函数定义 | 包括返回类型、函数名、参数列表和函数体 |
参数传递 | 值传递(副本)、地址传递(指针)、引用传递(别名) |
函数声明 | 提前告知编译器函数存在,定义可后置 |
分文件编写 | 头文件放声明(.h),源文件放实现(.cpp),提高代码可维护性 |
数组与函数 | 数组作为参数时传递地址,函数内可修改原始数组 |
掌握数组和函数是C++编程的基础,通过合理组织代码结构和数据存储,可以构建更复杂、高效的程序系统。