【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.mzph.cn/web/66090.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker save load 镜像 tag 为 <none>

一、场景分析 我从 docker hub 上拉了这么一个镜像。 docker pull tomcat:8.5-jre8-alpine 我用 docker save 命令想把它导出成 tar 文件以便拷贝到内网机器上使用。 docker save -o tomcat-8.5-jre8-alpine.tar.gz 镜像ID 当我把这个镜像传到别的机器&#xff0c;并用 dock…

O2O同城系统架构与功能分析

2015工作至今&#xff0c;10年资深全栈工程师&#xff0c;CTO&#xff0c;擅长带团队、攻克各种技术难题、研发各类软件产品&#xff0c;我的代码态度&#xff1a;代码虐我千百遍&#xff0c;我待代码如初恋&#xff0c;我的工作态度&#xff1a;极致&#xff0c;责任&#xff…

走出实验室的人形机器人,将复刻ChatGPT之路?

1月7日&#xff0c;在2025年CES电子展现场&#xff0c;黄仁勋不仅展示了他全新的皮衣和采用Blackwell架构的RTX 50系列显卡&#xff0c;更进一步展现了他对于机器人技术领域&#xff0c;特别是人形机器人和通用机器人技术的笃信。黄仁勋认为机器人即将迎来ChatGPT般的突破&…

EF Core执行原生SQL语句

目录 EFCore执行非查询原生SQL语句 为什么要写原生SQL语句 执行非查询SQL语句 有SQL注入漏洞 ExecuteSqlInterpolatedAsync 其他方法 执行实体相关查询原生SQL语句 FromSqlInterpolated 局限性 执行任意原生SQL查询语句 什么时候用ADO.NET 执行任意SQL Dapper 总…

Java中网络编程的学习

目录 网络编程概述 网络模型 网络通信三要素: IP 端口号 通信协议 IP地址&#xff08;Internet Protocol Address&#xff09; 端口号 网络通信协议 TCP 三次握手 四次挥手 UDP TCP编程 客户端Socket的工作过程包含以下四个基本的步骤&#xff1a; 服务器程序…

HarmonyOS NEXT开发进阶(七):页面跳转

文章目录 一、前言二、页面跳转三、页面返回四、页面返回前增加确认对话框4.1 系统的默认询问框4.2 自定义询问框 五、拓展阅读 一、前言 APP开发过程中&#xff0c;多页面跳转场景十分常见&#xff0c;例如&#xff0c;登录 -> 首页 -> 个人中心。在鸿蒙开发中&#xf…

【Python】第一弹---解锁编程新世界:深入理解计算机基础与Python入门指南

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【MySQL】【Python】 目录 1、计算机基础概念 1.1、什么是计算机 1.2、什么是编程 1.3、编程语言有哪些 2、Python 背景知识 2.…

学习threejs,使用FlyControls相机控制器

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.FlyControls 相机控制…

隐私计算,构建安全的未来数据空间

大数据产业创新服务媒体 ——聚焦数据 改变商业 在医疗领域&#xff0c;不同医院之间需要共享患者数据&#xff0c;以提供更全面准确的诊断和治疗方案。 传统的数据处理方式通常是数据经过转换隐藏重要数据后再进行分析&#xff0c;虽然可以保护数据隐私&#xff0c;但在数据源…

Java 面试中的高频算法题详解

&#x1f496; 欢迎来到我的博客&#xff01; 非常高兴能在这里与您相遇。在这里&#xff0c;您不仅能获得有趣的技术分享&#xff0c;还能感受到轻松愉快的氛围。无论您是编程新手&#xff0c;还是资深开发者&#xff0c;都能在这里找到属于您的知识宝藏&#xff0c;学习和成长…

【Python项目】手写数字识别系统

【Python项目】手写数字识别系统 技术简介&#xff1a;采用Python技术、Django框架、MYSQL数据库等实现。 系统简介&#xff1a;手写数字识别系统主要的功能有手写字识别、手写字管理、修改密码、个人信息和用户管理。 背景&#xff1a; 在当今这个飞速发展的时代&#xff0c;…

Springboot + vue 小区物业管理系统

&#x1f942;(❁◡❁)您的点赞&#x1f44d;➕评论&#x1f4dd;➕收藏⭐是作者创作的最大动力&#x1f91e; &#x1f496;&#x1f4d5;&#x1f389;&#x1f525; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;欢迎留言讨论 &#x1f525;&#x1f525;&…

空指针:HttpSession异常,SpringBoot集成WebSocket

异常可能性&#xff1a; 404 &#xff1a; 请检查拦截器是否将请求拦截WebSocket握手期间HttpSession为空 HttpSession为空 方法一 &#xff1a; 网上参考大量的文档&#xff0c;有说跟前端请求域名有关系的。 反正对我来说&#xff0c;没啥用无法连接。 需使用 localhost&a…

什么是视频孪生智慧能源?视频孪生智慧能源的应用案例

‌视频孪生智慧能源是集三维地理信息系统、视频虚实融合、数字孪生、人工智能等多技术于一体的综合应用&#xff0c;旨在实现对能源系统的实时、动态、全方位监控和管理‌。 具体来说&#xff0c;视频孪生智慧能源通过以下方式实现其功能&#xff1a; ‌技术融合‌&#xff1a;…

【update 更新数据语法合集】.NET开源ORM框架 SqlSugar 系列

系列文章目录 &#x1f380;&#x1f380;&#x1f380; .NET开源 ORM 框架 SqlSugar 系列 &#x1f380;&#x1f380;&#x1f380; 文章目录 系列文章目录前言 &#x1f343;一、实体对象更新1.1 单条与批量1.2 不更新某列1.3 只更新某列1.4 NULL列不更新1.5 无主键/指定列…

006-excel数据输出insert语句

一、在空白列插入&#xff0c;选择需要的列 "INSERT INTO tab_name1 (code, name) VALUES ("&A1&", "&B1&");"二、 拖动填充块&#xff0c;或者双击填充块&#xff08;可以快速填充整列&#xff09; 三、直接把生成的 insert 语…

前端组件开发:组件开发 / 定义配置 / 配置驱动开发 / 爬虫配置 / 组件V2.0 / form表单 / table表单

一、最早的灵感 最早的灵感来自sprider / 网络爬虫 / 爬虫配置&#xff0c;在爬虫爬取网站文章时候&#xff0c;会输入给爬虫一个配置文件&#xff0c;里边的内容是一个json对象。里边包含了所有想要抓取的页面的信息。爬虫通过这个配置就可以抓取目标网站的数据。其实本文要引…

43.Textbox的数据绑定 C#例子 WPF例子

固定最简步骤&#xff0c;包括 XAML&#xff1a; 题头里引入命名空间 标题下面引入类 box和block绑定属性 C#&#xff1a; 通知的类&#xff0c;及对应固定的任务 引入字段 引入属性 属性双触发&#xff0c;其中一个更新block的属性 block>指向box的属性 从Textbo…

excel按行检索(index+match)

假设你的数据表如下&#xff1a; 假设 数据区域是 A1:D4。 你想查询某人在某个日期的数据。 实现步骤 公式 在某个单元格中使用以下公式&#xff1a; excel 复制代码 INDEX(A2:D4, MATCH(“张三”, A2:A4, 0), MATCH(“2025/01/02”, A1:D1, 0)) 2. 公式拆解 MATCH(“张三”,…