在C语言中,数组名作为函数参数时,实际传递的是数组的首地址(退化为指针),因此函数内部无法通过sizeof获取原始数组大小,必须额外传递数组长度参数(如int n),以确保正确遍历和处理数组元素,避免访问越界错误。

在C语言中,数组名作为函数参数是常见且重要的用法。理解其工作原理对正确使用C语言至关重要。

一、本质原理

  1. 数组名的本质

    • 数组名代表数组的首地址(即数组第一个元素的地址)
    • 数组名是常量标识符,不能被修改(不能进行arr++等操作)
    • 数组名在表达式中会"退化"为指向首元素的指针
  2. 作为函数参数时的行为

    • 当数组名作为函数参数传递时,实际传递的是数组的首地址
    • 函数内部将数组名视为指针(int *arr),而非真正的数组
    • 重要区别:在函数内部,sizeof(arr)返回的是指针的大小(4或8字节),而不是数组的大小

二、为什么需要传递数组长度

由于数组名在函数内部退化为指针,函数无法知道原始数组的大小,因此必须额外传递数组长度

// 正确用法:传递数组名和数组长度
int Array_Sum(int array[], int n); 

// 错误用法:仅传递数组名
int Array_Sum(int array[]); // 无法知道数组长度

三、正确使用示例

#include <stdio.h>

// 函数声明
int Array_Sum(int array[], int n); 

int main(void)
{
    int a[] = {11, 22, 33, 44, 55, 66, 77, 88};
    
    // 计算数组长度
    int size = sizeof(a) / sizeof(a[0]); 
    
    printf("数组中各个元素之和 sum = %d\n", Array_Sum(a, size));
    return 0;
}

int Array_Sum(int array[], int n)
{
    int i, sum = 0;
    for(i = 0; i < n; i++)
    {
        sum += array[i];
    }
    return sum;
}

四、关键点总结

  1. 数组名作为参数

    • 传递的是数组的首地址
    • 函数内部将数组名视为指针(int *arr
    • sizeof(array)在函数内部返回指针大小,不是数组大小
  2. 数组长度计算

    • 必须在调用函数前计算数组长度:size = sizeof(array) / sizeof(array[0])
    • 不能在函数内部使用sizeof计算数组长度
  3. 形参数组大小声明

    • 在函数声明中,int array[10]中的10会被忽略,编译器会将其视为int *array
    • 形参中的数组大小声明是无效的
  4. 为什么不能只传递数组名

    • 无法知道数组有多少个元素
    • 会导致访问越界或程序崩溃

五、常见错误

// 错误示例:在函数内部尝试使用sizeof获取数组大小
void func(int arr[]) {
    int size = sizeof(arr); // 这里size是4或8,不是数组大小
    // 无法正确计算数组元素个数
}

六、正确做法

// 正确做法:传递数组名和数组长度
void processArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        // 处理数组元素
    }
}

int main() {
    int data[5] = {1, 2, 3, 4, 5};
    int size = sizeof(data) / sizeof(data[0]);
    processArray(data, size);
}

七、数组名与指针的本质区别

特性数组名指针
本质常量标识符,代表整个数组的首地址变量,存储地址的容器
sizeof返回整个数组的大小(元素个数×元素大小)返回指针本身的大小(4或8字节)
可修改性不能重新赋值(常量)可以重新赋值(变量)
作为函数参数退化为指针传递指针的副本

理解这些区别能避免在C语言编程中常见的数组处理错误,特别是数组长度计算和越界访问问题。