C语言中,数组名和指针之间有着密切的关系,但它们并不完全相同。理解它们之间的区别和联系对于掌握C语言的内存管理和数据结构至关重要。数组名是一个常量指针,指向数组的起始地址,而指针变量可以被重新赋值。

1、数组名和指针的关系

数组名是一个标识符,代表数组的首地址,即数组第一个元素的地址。指针是一个变量,存储某个内存地址的值,并且它可以改变指向不同的内存位置。

#include <stdio.h>

int main() {
    int arr[3] = {10, 20, 30};
    int *ptr = arr;  // 数组名 arr 表示数组首元素的地址

    printf("arr[0] = %d\n", arr[0]);  // 输出 10
    printf("*ptr = %d\n", *ptr);      // 输出 10

    return 0;
}

2、数组名与指针的区别

数组名本质上是一个常量指针,它指向数组的第一个元素。数组名在大多数情况下会被隐式转换为指向数组第一个元素的指针。指针是一个变量,它存储的是另一个变量的内存地址。指针可以被赋值、递增、递减,以及进行各种指针运算。

1)类型

数组名是一个常量指针,不能被重新赋值。

指针是一个变量,可以被重新赋值。

2)内存分配

数组名在声明时会分配一段连续的内存空间。

指针在声明时只会分配存储地址的空间,指向的内存空间需要显式分配。

3)sizeof运算符

sizeof(数组名)返回整个数组的大小(以字节为单位)。

sizeof(指针)返回指针本身的大小(通常是4或8字节,取决于系统)。

4)数组名作为函数参数

当数组名作为函数参数传递时,它会被转换为指向数组第一个元素的指针。

指针作为函数参数传递时,传递的是指针的副本。

#include <stdio.h>

int main() {
    int arr[3] = {10, 20, 30};
    int *ptr = arr;

    // 错误:数组名不能作为左值赋值
    // arr = ptr;  // 编译错误

    ptr++;  // 合法:指针可以移动到下一个元素
    printf("Next element: %d\n", *ptr);  // 输出 20

    return 0;
}

3、数组名与指针在函数参数中的行为

当数组作为参数传递给函数时,数组名会退化为指针,即传递的是数组首元素的地址。也就是函数中无法获取数组的大小,只能访问数组元素。

#include <stdio.h>

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

int main() {
    int arr[3] = {10, 20, 30};
    printArray(arr, 3);  // 传递数组名,相当于传递指针

    return 0;
}

4、使用 sizeof 的区别

数组名中的sizeof(arr) 返回整个数组的大小(字节数)。指针中的sizeof(ptr) 返回指针的大小(通常是8字节)。

#include <stdio.h>

int main() {
    int arr[3] = {10, 20, 30};
    int *ptr = arr;

    printf("Size of arr: %zu\n", sizeof(arr));  // 输出 12(3 * sizeof(int))
    printf("Size of ptr: %zu\n", sizeof(ptr));  // 输出 8(指针大小)

    return 0;
}

5、数组名与指针的访问方式

数组名可以用于指向数组的首地址,类似于指针。数组名可以用于指向数组的首地址,类似于指针。

#include <stdio.h>

int main() {
    int arr[3] = {10, 20, 30};
    int *ptr = arr;

    // 使用数组名和指针访问元素
    printf("arr[1] = %d\n", arr[1]);
    printf("*(ptr + 1) = %d\n", *(ptr + 1));  // 等价于 arr[1]

    return 0;
}