欢迎光临
我们一直在努力

C语言中数组的定义操作与常见算法

一、数组的基本概念与分类

1. 核心定义

数组是相同数据类型、有限个元素的有序集合。其核心特性的:

  • 连续性:数组元素在内存中占用连续的存储空间;
  • 有序性:元素通过 “下标”(索引)唯一标识,下标从 0 开始;
  • 单一性:所有元素必须是同一种数据类型(如 int、float 等)。

2. 数组的分类

根据维度不同,数组可分为:

  • 一维数组:最常用的形式,如int a[5](存储 5 个整数);
  • 二维数组:本质是 “数组的数组”,如int a[3][4](3 行 4 列的整数矩阵);
  • 多维数组:二维以上的数组(如三维数组int a[2][3][4]),实际开发中较少使用。

本文重点讲解一维数组的使用(二维及多维数组可类比推导)。

二、一维数组的定义与初始化

1. 数组的定义

定义格式:数据类型 数组名[元素个数];

  • 数据类型:数组元素的统一类型(如 int、float、char 等);
  • 数组名:符合 C 语言命名规则(字母、数字、下划线组成,不能以数字开头);
  • 元素个数:必须是常量或常量表达式(不能是变量),表示数组能存储的元素总数。

2. 数组的初始化

数组定义后若未初始化,元素值为随机值(内存中的垃圾数据),因此建议显式初始化。常见初始化方式有 3 种:

(1)全部初始化

显式指定所有元素的值,元素个数与初始化列表长度一致:

(2)局部初始化

只指定部分元素的值,未指定的元素会自动初始化为 0:

(3)默认初始化

不指定元素个数,编译器会根据初始化列表的长度自动推导数组长度:

3. 关键注意事项

  • 数组下标范围:合法下标是0 ~ 元素个数-1,例如int arr[5]的合法下标是 0-4,访问arr[5]属于越界访问,会导致内存错误(如栈溢出);
  • 数组长度计算:通过sizeof(arr) / sizeof(arr[0])可动态计算数组长度(避免硬编码,提高代码复用性)

三、数组的基本操作:输入与输出

数组元素的访问通过 “数组名 [下标]” 实现,结合循环可批量完成输入 / 输出。

1. 数组输入(从终端读取数据)

使用scanf结合for循环,遍历数组并接收用户输入:

#include <stdio.h>

int main(void) {
int arr[5] = {0};
int len = sizeof(arr) / sizeof(arr[0]);
int i = 0;

printf("请输入%d个整数:\\n", len);
for (i = 0; i < len; i++) {
// &arr[i]:取第i个元素的内存地址(scanf需要地址参数)
scanf("%d", &arr[i]);
}
return 0;
}

2. 数组输出(向终端打印数据)

使用printf结合for循环,遍历数组并打印元素:

// 接上面的输入代码,添加输出逻辑
printf("数组元素:");
for (i = 0; i < len; i++) {
// 打印第i个元素,加空格分隔
printf("%d ", arr[i]);
}
printf("\\n");

请输入5个整数:
3 1 4 2 5
数组元素:3 1 4 2 5

四、数组常见算法实战

数组的核心应用是批量数据处理,以下是 3 个最常用的算法(含完整代码)。

1. 求数组的最大值(及最大值下标)

算法思路:
  • 假设数组第一个元素为初始最大值(max = arr[0]);
  • 从第二个元素开始遍历数组,若当前元素大于max,则更新max;
  • 若需获取最大值下标,只需同步记录最大值对应的索引即可。
  • 完整代码:

    #include <stdio.h>

    int main(void) {
    int arr[5] = {0};
    int len = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    int max_val = 0; // 存储最大值
    int max_idx = 0; // 存储最大值下标

    // 输入数组
    printf("请输入%d个整数:\\n", len);
    for (i = 0; i < len; i++) {
    scanf("%d", &arr[i]);
    }

    // 初始化最大值为第一个元素
    max_val = arr[0];
    for (i = 1; i < len; i++) {
    if (arr[i] > max_val) {
    max_val = arr[i]; // 更新最大值
    max_idx = i; // 更新最大值下标
    }
    }

    // 输出结果
    printf("数组最大值:%d\\n", max_val);
    printf("最大值下标:%d\\n", max_idx);
    return 0;
    }

    请输入5个整数:
    3 1 4 2 5
    数组最大值:5
    最大值下标:4

    2. 数组元素倒置(逆序)

    算法思路:

    将数组 “首尾元素互换”,直到中间位置:

  • 定义循环变量i从 0 开始,遍历到len/2(避免重复交换);
  • 第i个元素与第len-1-i个元素交换(如 i=0 时,交换第一个和最后一个元素);
  • 用临时变量tmp辅助交换。
  • 完整代码:

    #include <stdio.h>

    int main(void) {
    int arr[5] = {1, 2, 3, 4, 5};
    int len = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    int tmp = 0; // 临时变量,用于交换元素

    // 倒置前输出
    printf("倒置前数组:");
    for (i = 0; i < len; i++) {
    printf("%d ", arr[i]);
    }
    printf("\\n");

    // 数组倒置
    for (i = 0; i < len / 2; i++) {
    // 交换arr[i]和arr[len-1-i]
    tmp = arr[i];
    arr[i] = arr[len – 1 – i];
    arr[len – 1 – i] = tmp;
    }

    // 倒置后输出
    printf("倒置后数组:");
    for (i = 0; i < len; i++) {
    printf("%d ", arr[i]);
    }
    printf("\\n");
    return 0;
    }

    倒置前数组:1 2 3 4 5
    倒置后数组:5 4 3 2 1

    3. 数组排序:冒泡排序与选择排序

    排序是数组最核心的应用之一,以下讲解两种基础且常用的排序算法(升序排列)。

    (1)冒泡排序
    算法思路:

    通过相邻元素两两比较并交换,将 “大数” 逐步 “冒泡” 到数组末尾:

  • 外层循环控制排序轮数:共需len-1轮(最后一个元素无需比较);
  • 内层循环控制每轮比较次数:每轮比较len-1-j次(j 为当前轮数,末尾 j 个元素已排好序);
  • 若arr[i] > arr[i+1],则交换两者(升序逻辑)。
  • 完整代码:

    #include <stdio.h>

    int main(void) {
    int arr[5] = {0};
    int len = sizeof(arr) / sizeof(arr[0]);
    int i = 0, j = 0;
    int tmp = 0;

    // 输入数组
    printf("请输入%d个整数:\\n", len);
    for (i = 0; i < len; i++) {
    scanf("%d", &arr[i]);
    }

    // 冒泡排序(升序)
    for (j = 0; j < len – 1; j++) { // 外层:排序轮数(len-1轮)
    for (i = 0; i < len – 1 – j; i++) { // 内层:每轮比较次数
    if (arr[i] > arr[i + 1]) { // 相邻元素比较,大数后移
    tmp = arr[i];
    arr[i] = arr[i + 1];
    arr[i + 1] = tmp;
    }
    }
    }

    // 输出排序结果
    printf("排序后数组:");
    for (i = 0; i < len; i++) {
    printf("%d ", arr[i]);
    }
    printf("\\n");
    return 0;
    }

    (2)选择排序
    算法思路:

    每轮找到数组中最小元素的下标,与当前轮的起始位置元素交换:

  • 外层循环控制起始位置:从 0 到len-1(最后一个元素无需比较);
  • 内层循环查找最小元素下标:从起始位置j开始,找到最小元素的索引min_idx;
  • 若min_idx != j,交换arr[j]和arr[min_idx](避免自身交换)。
  • 完整代码:

    #include <stdio.h>

    int main(void) {
    int arr[5] = {0};
    int len = sizeof(arr) / sizeof(arr[0]);
    int i = 0, j = 0;
    int tmp = 0;
    int min_idx = 0; // 存储最小元素下标

    // 输入数组
    printf("请输入%d个整数:\\n", len);
    for (i = 0; i < len; i++) {
    scanf("%d", &arr[i]);
    }

    // 选择排序(升序)
    for (j = 0; j < len – 1; j++) { // 外层:起始位置
    min_idx = j; // 假设当前起始位置是最小值
    // 内层:查找最小元素下标
    for (i = j + 1; i < len; i++) {
    if (arr[i] < arr[min_idx]) {
    min_idx = i; // 更新最小元素下标
    }
    }
    // 交换当前起始位置与最小元素位置
    if (min_idx != j) {
    tmp = arr[j];
    arr[j] = arr[min_idx];
    arr[min_idx] = tmp;
    }
    }

    // 输出排序结果
    printf("排序后数组:");
    for (i = 0; i < len; i++) {
    printf("%d ", arr[i]);
    }
    printf("\\n");
    return 0;
    }

    两种排序算法对比:

    算法核心特点时间复杂度
    冒泡排序 相邻元素交换,逻辑简单 O(n²)
    选择排序 先找最小下标再交换,交换次数少 O(n²)

    五、数组常见问题与避坑指南

  • 数组越界访问:这是最常见的错误!例如int arr[5]访问arr[5],会导致内存破坏(如栈溢出stack smashing detected)。解决:严格控制循环条件(i < len),避免下标超出0~len-1。
  • 数组名不可修改:数组名是常量(指向数组首元素的地址),不能直接赋值(如arr = {1,2,3}是错误的),只能通过下标修改单个元素。
  • 初始化与赋值混淆:数组初始化只能在定义时进行,定义后不能用arr = {1,2,3}批量赋值,需通过循环逐个修改。
  • 整数除法误差:若数组存储成绩等需要计算平均值的场景,需用浮点型(double)存储结果,避免整数除法丢失精度(如(double)sum / len)。
  • 赞(0)
    未经允许不得转载:171主机测评 » C语言中数组的定义操作与常见算法
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址