1、数组参数会退化为指针的原因
C语言中,数组作为参数传递给函数时实际上传递的是指向数组首元素的指针,而不是整个数组。这样设计的原因是效率:传递指针比传递整个数组要高效得多。
因此,当你在函数中定义一个数组参数时,比如 int arr[]
或 int arr[10]
,编译器将其视为 int* arr
,即一个指向 int
的指针,而不是实际的数组。由于 arr
退化为指针,调用 sizeof(arr)
会返回指针的大小,而不是数组的大小。
#include <stdio.h>
void printArraySize(int arr[]) {
printf("Size of array parameter in function: %zu bytes\n", sizeof(arr));
}
int main() {
int arr[10]; // 定义一个大小为10的数组
printf("Size of array in main: %zu bytes\n", sizeof(arr));
printArraySize(arr); // 传递数组到函数
return 0;
}
2、函数中获取数组的实际大小的方法
由于数组在传递给函数时会退化为指针,如果我们需要在函数中知道数组的实际大小,可以通过传递数组的长度信息。
#include <stdio.h>
void printArray(int arr[], size_t size) {
printf("Array size in function: %zu\n", size);
for (size_t i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
size_t size = sizeof(arr) / sizeof(arr[0]); // 计算数组元素个数
printf("Array size in main: %zu\n", size);
printArray(arr, size); // 将数组和大小传递给函数
return 0;
}
3、函数中使用指针加长度的方式
使用指针加长度的方式传递数组时,我们将数组的首地址和数组的长度一同传递给函数。这样,函数可以使用指针来操作数组,并根据传入的长度来遍历数组。
#include <stdio.h>
void printArray(int *arr, int length) {
for (int i = 0; i < length; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
int length = sizeof(arr) / sizeof(arr[0]); // 计算数组长度
printArray(arr, length); // 传递数组指针和长度
return 0;
}
4、数组首地址和指针区别
数组首地址,在 sizeof(arr)
中,arr 是整个数组,sizeof(arr)
返回整个数组的大小。指针,在 sizeof(ptr)
中,ptr
是一个指针变量,sizeof(ptr)
返回的是指针的大小(通常在 32
位系统上是 4
字节,在 64
位系统上是 8
字节),与数组大小无关。
当数组作为参数传递给函数时,数组会退化为指针,传递的实际上是数组首地址,而不是整个数组。即使在函数定义中使用数组的形式(如 int arr[]
),本质上它等同于指针 int *arr。指针作为参数传递时,本质上就是传递指针的值(地址),并且在函数内部可以改变指针指向的内容。
#include <stdio.h>
void foo(int arr[]) {
// 在函数中,数组名退化为指针
printf("Inside foo, sizeof(arr): %zu (array as parameter, treated as pointer)\n", sizeof(arr));
}
int main() {
int arr[5] = {1, 2, 3, 4, 5}; // 定义一个数组
int *ptr = arr; // 指针指向数组首地址
// sizeof 运算符的不同
printf("Size of array (sizeof(arr)): %zu (total array size)\n", sizeof(arr));
printf("Size of pointer (sizeof(ptr)): %zu (pointer size)\n", sizeof(ptr));
// 修改指针的指向
printf("Pointer before incrementing: %p\n", (void *)ptr);
ptr++; // 合法,指针可以移动到下一个元素
printf("Pointer after incrementing: %p\n", (void *)ptr);
// 尝试直接修改数组名(会报错,注释掉以防止编译错误)
// arr = ptr; // 错误:数组名是常量,不能赋值
// 调用函数,观察数组在函数中的行为
foo(arr);
return 0;
}