当前位置: 首页 > article >正文

【C】数组和指针的关系

C 语言C++ 中,数组和指针 有非常密切的关系。它们在某些情况下表现类似,但也有重要的区别。理解数组和指针的关系对于掌握低级内存操作和优化程序性能至关重要。


1. 数组和指针的基本关系

  • 数组是一个 连续存储的元素集合,在内存中占据一段连续的地址空间。
  • 数组的名称(如 arr)在很多情况下会退化为指向数组第一个元素的指针

1.1 数组名是一个指针的表现

假设有一个数组:

int arr[5] = {1, 2, 3, 4, 5};
  1. 数组名的含义:

    • arr 是一个常量指针,指向数组的第一个元素(&arr[0])。
    • arr 的类型是 int*
  2. 数组元素的访问:

    • arr[i] 等价于 *(arr + i)
    • 例如:
      printf("%d\n", arr[2]);  // 输出 3
      printf("%d\n", *(arr + 2));  // 等价于上面
      
  3. 地址的访问:

    • arr 是数组第一个元素的地址:&arr[0]
    • &arr 是整个数组的地址,类型是 int (*)[5],和 &arr[0] 不同。
    • 示例:
      printf("%p\n", arr);     // 输出数组第一个元素的地址
      printf("%p\n", &arr[0]); // 等价于 arr
      printf("%p\n", &arr);    // 输出整个数组的地址(类型是 int (*)[5])
      

2. 数组和指针的区别

尽管数组名和指针表现很相似,但它们并不完全相同:

2.1 内存分配

  • 数组
    • 数组是一个固定大小的内存块,在定义时分配内存。
    • 例如:
      int arr[5]; // 为数组分配了连续的 5 个 int 空间
      
  • 指针
    • 指针是一个变量,它存储的是地址,可以动态指向不同的位置。
    • 例如:
      int* ptr;
      ptr = malloc(5 * sizeof(int)); // 动态分配 5 个 int 空间
      

2.2 数组名是常量,指针是变量

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

    • 示例:
      int arr[5];
      arr = arr + 1; // 错误,数组名不能作为左值
      
  • 指针是变量,可以随时指向其他地址。

    • 示例:
      int* ptr;
      int x = 10, y = 20;
      ptr = &x; // 指向 x
      ptr = &y; // 可以改变指向,指向 y
      

2.3 使用 sizeof 的区别

  • 对数组和指针使用 sizeof 的结果不同:

    • 数组 返回整个数组的大小。
    • 指针 返回指针变量本身的大小(通常是 4 或 8 字节,取决于系统架构)。

    示例:

    int arr[5] = {1, 2, 3, 4, 5};
    int* ptr = arr;
    
    printf("%zu\n", sizeof(arr)); // 输出 20(5 个 int 的大小)
    printf("%zu\n", sizeof(ptr)); // 输出 8(指针本身的大小,假设是 64 位系统)
    

2.4 数组和指针的类型

  • 数组名和指针的类型不同:
    • arr 的类型是 int[5],退化后是 int*
    • ptr 的类型是 int*,可以自由赋值。

3. 数组和指针在函数中的关系

3.1 数组作为函数参数时会退化为指针

当数组作为函数参数传递时,数组会退化为指针传递,函数实际上接收到的是指向数组第一个元素的指针。

示例:

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

int main()
{
    int arr[5] = {1, 2, 3, 4, 5};
    printArray(arr, 5); // 传递的是 int* 指针
    return 0;
}
实际的函数签名

上述函数 void printArray(int arr[], int size) 实际等价于:

void printArray(int* arr, int size);

3.2 多维数组的函数参数

多维数组的第一级会退化为指针,但其余维度需要明确指定大小。

示例:

void print2DArray(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");
    }
}

int main()
{
    int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
    print2DArray(arr, 2); // 传递的是 int (*)[3] 指针
    return 0;
}
注意
  • 函数参数中必须指定第二维(3),因为编译器需要知道每行的长度。

4. 结合使用数组和指针的技巧

4.1 动态分配多维数组

可以使用指针动态分配多维数组,而不是直接定义多维数组。

示例:

int** create2DArray(int rows, int cols)
{
    int** arr = malloc(rows * sizeof(int*)); // 分配行指针
    for (int i = 0; i < rows; i++)
    {
        arr[i] = malloc(cols * sizeof(int)); // 分配每行的数据
    }
    return arr;
}

4.2 遍历数组的指针操作

可以使用指针运算遍历数组,而不使用下标。

示例:

int arr[5] = {1, 2, 3, 4, 5};
int* ptr = arr; // 指向数组第一个元素

for (int i = 0; i < 5; i++)
{
    printf("%d ", *(ptr + i)); // 使用指针访问元素
}

5. 小结

数组和指针的相似点:

  1. 数组名可以退化为指向第一个元素的指针。
  2. 数组元素可以通过下标或指针运算访问。

数组和指针的区别:

  1. 数组名是常量指针,指针变量可以自由赋值。
  2. sizeof 操作在数组和指针上有不同的行为。
  3. 数组有固定大小,指针可以动态指向不同的位置。

http://www.kler.cn/a/505587.html

相关文章:

  • citrix netscaler13.1 重写负载均衡响应头(基础版)
  • React 第三方状态管理库相关 -- Redux MobX 篇
  • Deep4SNet: deep learning for fake speech classification
  • 从源码角度分析SpringMVC执行流程
  • LeetCode 热题 100_从前序与中序遍历序列构造二叉树(47_105_中等_C++)(二叉树;递归)
  • 机器学习(1):线性回归概念
  • Ubuntu 安装和配置 MariaDB
  • 【行空板K10】上传温湿度信息到EasyIoT平台
  • redis闪退打不开Creating Server TCP listening socket *:6379: listen: Unknown error
  • ESP8266固件烧录
  • 利用Python爬虫按图搜索1688商品(拍立淘)的探索之旅
  • 从CRUD到高级功能:EF Core在.NET Core中全面应用(二)
  • 鸿蒙报错Init keystore failed: keystore password was incorrect
  • 【element plus】虚拟dom表格中cellRenderer如何使用v-for循环渲染item
  • 【vue3】 defineExpose 的使用
  • IIO(Industrial I/O)驱动介绍
  • 使用分割 Mask 和 K-means 聚类获取天空的颜色
  • 爬虫后的数据处理与使用(使用篇--实现分类预测)
  • css 三角构建
  • MCU中实时时钟(RTC)和普通定时器有什么区别
  • 深入Android架构(从线程到AIDL)_32 JNI架构原理_Java与C的对接05
  • C -- 大端对齐 小端对齐 的人性化解释
  • HTTP 缓存机制详解
  • matlab专栏-M文件
  • 学生资助在线管理软件开发微信小程序ssm+论文源码调试讲解
  • 《AI发展的三个关键视角:基础设施、开源趋势与社会影响》