【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,一经查实,立即删除!

相关文章

Maven 配置本地仓库

步骤 1&#xff1a;修改 Maven 的 settings.xml 文件 找到你的 Maven 配置文件 settings.xml。 Windows: C:\Users\<你的用户名>\.m2\settings.xmlLinux/macOS: ~/.m2/settings.xml 打开 settings.xml 文件&#xff0c;找到 <localRepository> 标签。如果没有该标…

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…

《盘古大模型——鸿蒙NEXT的智慧引擎》

在当今科技飞速发展的时代&#xff0c;华为HarmonyOS NEXT的发布无疑是操作系统领域的一颗重磅炸弹&#xff0c;其将人工智能与操作系统深度融合&#xff0c;开启了智能新时代。而盘古大模型在其中发挥着至关重要的核心作用。 赋予小艺智能助手超强能力 在鸿蒙NEXT中&#xf…

走出实验室的人形机器人,将复刻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.…

LeetCode:131. 分割回文串

跟着carl学算法&#xff0c;本系列博客仅做个人记录&#xff0c;建议大家都去看carl本人的博客&#xff0c;写的真的很好的&#xff01; 代码随想录 LeetCode:131. 分割回文串 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是回文串。返回 s 所…

优化神马关键词排名原理(优化神马搜索引擎关键词排名规则)

优化神马&#xff08;即百度&#xff09;关键词排名的原理主要基于搜索引擎的算法和用户体验的考量。以下是一些关键的优化原理&#xff1a; 一、搜索引擎算法 网页重要性评估&#xff1a; 搜索引擎通过复杂的算法评估网页的重要性和权威性&#xff0c;如基于PageRank的评估方…

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

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

Vue 3前端与Python(Django)后端接口简单示例

项目 后端&#xff08;Django&#xff09;前端&#xff08;Vue 3&#xff09; 后端&#xff08;Django&#xff09; 创建Django项目和应用&#xff1a; 确保你已经安装了Django。如果没有安装&#xff0c;可以使用以下命令安装&#xff1a; pip install django创建一个新的Dja…

MCP Server开发的入门教程(python和pip)

使用python技术栈开发的简单mcp server 需要安装 MCP server的需要使用python-sdk,python需要 3.10,安装如下 pip install mcpPS: MCP官方使用的是uv包管理工具,我平时使用pip比较多,所以文中以pip为主。因为mcp的一些依赖包版本并不是最新的,所以最好弄一个干净的环境…

Spark vs Flink分布式数据处理框架的全面对比与应用场景解析

1. 引言 1.1 什么是分布式数据处理框架 随着数据量的快速增长&#xff0c;传统的单机处理方式已经无法满足现代数据处理需求。分布式数据处理框架应运而生&#xff0c;它通过将数据分片分布到多台服务器上并行处理&#xff0c;提高了任务的处理速度和效率。 分布式数据处理框…

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

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

PID控制器 (Proportional-Integral-Derivative Controller) 算法详解及案例分析

PID控制器 (Proportional-Integral-Derivative Controller) 算法详解及案例分析 目录 PID控制器 (Proportional-Integral-Derivative Controller) 算法详解及案例分析1. 引言2. PID控制器的基本概念2.1 PID控制器的定义2.2 PID控制器的核心思想2.3 PID控制器的应用领域3. PID控…

rtthread学习笔记系列(3) -- FINSH模块

文章目录 3. FINSH模块3.1MSH3.1.1初始化3.1.1.1FSymtab段3.1.1.2 宏 3.1.2遍历FINSH命令3.1.3TAB补全实现3.1.3.1 msh_auto_complete3.1.3.2 msh_opt_auto_complete 3.1.4 TAB 子选项自动补全 3.2 SHELL3.2.1 finsh_system_init分配finsh结构体使用内存3.2.2 finsh_thread_ent…

Redis 知识速览

文章目录 1. Redis 简介2. Redis 优缺点3. Redis 高性能4. Redis VM 机制5. Redis 数据类型6. 应用场景7. 持久化8. 过期策略9. 内存相关10. 线程模型11. 事务12. 集群 1. Redis 简介 定义&#xff1a;Redis 是一个用 C 语言编写的高性能非关系型&#xff08;NoSQL&#xff09…