C 语言 | 在函数中操作数组

1. 引言

在 C 语言中,数组以特殊的方式传递给函数。当你将数组传递给函数时,实际传递的是指向其第一个元素的指针。这意味着函数操作的是原始数组,而不是副本。理解这一行为对于编写高效且正确的 C 程序至关重要。

2. 数组如何传递给函数

当你编写一个接受数组作为参数的函数时,编译器会将参数视为指针。例如,以下两个函数声明是等价的:

c 复制代码
void print_array(int arr[], int size);
void print_array(int *arr, int size);

两者都告诉编译器 arr 指向一个整数数组的第一个元素。由于数组是通过引用(即指针)传递的,函数内部所做的任何修改都会影响调用者中的原始数组。

3. 将数组传递给函数

要将数组传递给函数,只需使用不带方括号的数组名。数组名会退化为指向其第一个元素的指针。

c 复制代码
#include <stdio.h>

void print_array(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int numbers[] = {10, 20, 30, 40, 50};
    int n = sizeof(numbers) / sizeof(numbers[0]);

    print_array(numbers, n);
    return 0;
}

输出:

复制代码
10 20 30 40 50

注意,在 main 函数中,sizeof(numbers) 给出的是数组的总字节数,因此除以 sizeof(numbers[0]) 可以得到元素的个数。然而,在函数内部,sizeof(arr) 只会给出指针的大小,而不是整个数组的大小。这就是为什么必须显式传递数组大小的原因。

4. 在函数内部修改数组

由于数组是通过引用传递的,你可以在函数内部直接修改原始数组,而无需返回任何内容。

c 复制代码
#include <stdio.h>

void double_values(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        arr[i] *= 2;
    }
}

int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    int n = sizeof(numbers) / sizeof(numbers[0]);

    double_values(numbers, n);

    for (int i = 0; i < n; i++) {
        printf("%d ", numbers[i]);
    }
    printf("\n");
    return 0;
}

输出:

复制代码
2 4 6 8 10

函数 double_values 直接修改了 numbers 的元素,这些修改在调用返回后于 main 函数中仍然可见。

5. 使用指针运算

由于数组参数实际上是一个指针,你可以在函数内部使用指针运算来遍历数组。

c 复制代码
#include <stdio.h>

int sum_array(int *arr, int size) {
    int total = 0;
    for (int i = 0; i < size; i++) {
        total += *(arr + i);
    }
    return total;
}

int main() {
    int numbers[] = {5, 10, 15, 20};
    int n = sizeof(numbers) / sizeof(numbers[0]);

    int result = sum_array(numbers, n);
    printf("Sum: %d\n", result);
    return 0;
}

输出:

复制代码
Sum: 50

在这里,*(arr + i) 等价于 arr[i]。两种形式访问的是同一个元素。

6. 二维数组

传递二维数组时需要指定第二维的大小,因为编译器需要知道每一行有多少列,才能正确计算地址。

c 复制代码
#include <stdio.h>

void print_matrix(int matrix[][3], int rows) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }
}

int main() {
    int grid[][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    print_matrix(grid, 3);
    return 0;
}

输出:

复制代码
1 2 3
4 5 6
7 8 9

参数 int matrix[][3] 表示一个指向包含 3 个整数的数组的指针。第一个维度可以省略,但第二个维度必须存在。

7. 常见陷阱

  • 忘记传递数组大小 :在函数内部,sizeof(arr) 返回的是指针的大小,而不是数组的大小。务必显式传递元素的个数。
  • 在只需要读取时却进行了修改 :如果函数不应修改数组,应将参数声明为 const int arr[],以防止意外修改。
  • 误以为数组会被复制:数组在传递给函数时永远不会被复制。如果需要副本,请在函数内部手动创建。

8. 总结

  • 数组作为指向其第一个元素的指针传递给函数。
  • 函数内部的修改会影响原始数组。
  • 始终单独传递数组的大小。
  • 使用 const 保护只读数组。
  • 对于多维数组,除第一维外,必须指定所有维度。

掌握在函数中操作数组是编写简洁高效 C 代码的关键一步。

相关推荐
Rabitebla7 小时前
【Linux】进程控制(十二) 自定义 Shell(二):内建命令与进程工作目录管理
linux·c++·笔记·学习·bash
码客-ygluu13 小时前
一个通用游戏数据服务器
c++·架构
another heaven13 小时前
【C/C++ Ranges 是零开销抽象吗?拆开管道、惰性求值和编译期膨胀】
c语言·开发语言·c++
Code_Solitude13 小时前
C语言动态内存 + 柔性数组 + 数组名退化
c语言·算法·柔性数组
上海潭龙东海科技有限公司13 小时前
客运站管控之动态孪生技术方案(新增一屏管控模块
数据仓库·人工智能·算法·重构·动态规划
YLCHUP16 小时前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
xiaoye-duck16 小时前
《C++ 项目:手写大模型接入 SDK》会话模块整合:内存 SessionManager 与 DataManager 持久化联动
开发语言·数据库·c++·语言模型
思麟呀16 小时前
背包DP(01背包+完全背包)
c++·算法
Zwawa17 小时前
让屏幕动起来:OLED动画效果,丝滑光标、帧动画和一只贪吃蛇
c语言·单片机·嵌入式