计算机语言 · 2025年6月4日

深度解析 C 语言数组传参:规则与示例

引言

在 C 语言开发中,数组是最常用的数据结构之一。将数组作为函数参数传递时与传递普通变量有所不同,掌握其中的细节有助于开发人员编写更高效、可靠的代码。本文将系统介绍数组传参的几种常见场景和注意事项,并通过示例演示如何正确使用一维和二维数组作为参数。同时,我们还将结合实际需求,介绍如何在云端环境(如美国服务器)下进行高效编译与部署,优化跨境访问性能。


一、数组传参基础

当将数组传递给函数时,实际上传递的是数组首元素的地址,并不会在函数内部创建新的数组副本。换句话说,形参与实参共享同一块内存空间,因此在函数内部对数组元素的修改会影响到外部数组。

1. 数组名的含义

  • 一般情况下,数组名表示数组首元素地址。例如,arr 等价于 &arr[0]
  • 特殊情况一:sizeof(arr)
    #include <stdio.h>
    int main() {
        int arr[] = {1, 2, 3, 4, 5};
        printf("%zu\n", sizeof(arr)); // 输出数组总字节数(例如 20)
        return 0;
    }
    

    此时 sizeof(arr) 计算的是整个数组在内存中的字节大小,而非指针长度。

  • 特殊情况二:&arr
    #include <stdio.h>
    int main() {
        int arr[] = {1, 2, 3, 4, 5};
        printf("%p\n", (void *)arr);      // 输出数组首元素地址
        printf("%p\n", (void *)&arr);     // 输出数组整体地址
        return 0;
    }
    

    虽然 arr&arr 在初始打印结果相同,但当将指针加 1 时,差异会体现出来:

    printf("%p\n", (void *)(arr + 1));    // 跳过一个 int(即第一个元素)
    printf("%p\n", (void *)(&arr + 1));   // 跳过整个数组长度(例如 sizeof(int)*5)
    

二、实参传递时的特殊场景

2.1 使用 sizeof(arr) 计算元素个数

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50, 60};
    int count = sizeof(arr) / sizeof(arr[0]); // 得到元素个数 6
    printf("数组元素个数:%d\n", count);
    return 0;
}

对于希望在函数内部动态获取数组长度的场景,可通过上面方式在主函数中先计算,再将 count 传入函数。

2.2 使用 &arrarr 的指针差异

#include <stdio.h>

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    printf("arr     = %p\n", (void *)arr);
    printf("&arr    = %p\n", (void *)&arr);
    printf("arr + 1 = %p\n", (void *)(arr + 1));     // 跳过一个元素(4 字节)
    printf("&arr+1  = %p\n", (void *)(&arr + 1));   // 跳过整个数组(20 字节)
    return 0;
}

上例中,arr + 1 会移动到第二个元素地址,而 &arr + 1 会跳过整个数组内存块。


三、形参类型——数组名接收

3.1 一维数组作为形参

当函数形参声明为 int arr[]int arr[8] 时,实参传入的是首元素地址,形参内部无论使用哪种写法,均等同于 int *arr

#include <stdio.h>

// 将数组所有元素置为 -1
void set_to_minus_one(int arr[], int sz) {
    for (int i = 0; i < sz; i++) {
        arr[i] = -1;
    }
}

// 依次打印数组所有元素
void print_array(int arr[], int sz) {
    for (int i = 0; i < sz; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int data[] = {0, 1, 2, 3, 4, 5, 6, 7};
    int n = sizeof(data) / sizeof(data[0]); // 计算元素个数
    print_array(data, n);
    set_to_minus_one(data, n);
    print_array(data, n);
    return 0;
}

在主函数中对 data 进行修改后,set_to_minus_one 内部的修改会反映到主函数的 data 数组上。

3.2 二维数组作为形参

对于二维数组,行数可以省略,但列数必须显式指定且不可省略。例如:

#include <stdio.h>

// 将二维数组所有元素置为 -1
void set_matrix(int arr[][3], int rows) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 3; j++) {
            arr[i][j] = -1;
        }
    }
}

// 打印二维数组
void print_matrix(int arr[][3], int rows) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

int main() {
    int matrix[][3] = {
        {0, 1, 2},
        {3, 4, 5},
        {6, 7, 8}
    };
    int rows = sizeof(matrix) / sizeof(matrix[0]); // 行数
    print_matrix(matrix, rows);
    set_matrix(matrix, rows);
    print_matrix(matrix, rows);
    return 0;
}

上例中,arr[][3] 表示“行数省略、列数为 3”,传入函数时,实参与形参仍指向同一块内存。


四、形参类型——指针接收

除了使用数组名声明,形参也可以直接用指针接收数组首元素地址。对于一维数组,等效于上文的写法:

#include <stdio.h>

// 使用指针将数组所有元素置为 -1
void set_to_minus_one_ptr(int *arr, int sz) {
    for (int i = 0; i < sz; i++) {
        arr[i] = -1;
    }
}

// 依次打印数组元素
void print_array_ptr(int *arr, int sz) {
    for (int i = 0; i < sz; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int data[] = {0, 1, 2, 3, 4, 5, 6, 7};
    int n = sizeof(data) / sizeof(data[0]);
    print_array_ptr(data, n);
    set_to_minus_one_ptr(data, n);
    print_array_ptr(data, n);
    return 0;
}

不管是 int arr[] 还是 int *arr,核心都是操作同一片内存区域。


五、在美国服务器环境下的编译与部署建议

对于追求高性能和低延迟的项目,建议选择美国VPS美国云服务器来托管代码编译与调试环境:

  1. 跨境访问速度更优
    与国内服务器相比,美国节点对北美、欧洲及亚太部分地区访问延迟更低,尤其适合面向全球用户部署服务。
  2. 编译链与依赖管理
    在美国服务器上进行大规模编译与测试,可以充分利用其稳定带宽,快速下载开源依赖和软件包。
    示例(在 CentOS/Ubuntu 上安装 gcc 与 make):

    # Ubuntu 系统
    sudo apt-get update
    sudo apt-get install build-essential
    
    # CentOS 系统
    sudo yum groupinstall "Development Tools"
    
  3. 持续集成与自动化
    可在美国节点上配置 Jenkins、GitLab CI 等自动化测试和部署流水线,将 C 代码编译、单元测试、代码覆盖率分析等全流程集成在云端环境中,实现自动化持续集成。
  4. 数据库与缓存选型
    将 MySQL 或 PostgreSQL 安装在美国服务器,并结合 Redis 缓存,可为高并发项目提供稳定存储与快速读写能力。

结语

本文从数组传参的原理和示例出发,逐步深入介绍了一维、二维数组以及指针接收的用法,帮助读者掌握在函数中操作数组的正确方式。同时,我们还结合实际需求,分享了在美国服务器环境下部署 C 语言项目的实用建议,包括编译环境配置与持续集成方案。如果您计划将项目部署到美东或美西节点,获取更低网络延迟与更稳定的运行体验,推荐使用 美国服务器