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

C语言中的数组并非指针:深入理解数组和指针的区别

前言

在C语言中,数组和指针是两个非常重要的概念,它们在很多方面有着紧密的联系,但也存在显著的区别。尽管数组名有时可以像指针那样使用,但它们本质上并不是一回事。理解这些差异对于编写正确和高效的代码至关重要。本文将深入探讨数组和指针的区别,并提供一些示例代码。

381950c3d9a44c27b10d2fc1c418af1a.jpeg

1. 数组与指针的基础概念

  • 数组:数组是一系列相同类型数据的集合,它们在内存中连续存储。数组名本身是一个常量,指向数组的起始位置。
  • 指针:指针是一个变量,其值为另一个变量的地址。指针可以指向数组中的任何一个元素。

2. 数组与指针的相似之处

尽管数组和指针有很多不同之处,但它们在某些方面确实很相似:

  • 数组名作为指针:在许多上下文中,数组名可以被用作指向数组第一个元素的指针。
  • 指针算术:指针可以进行算术运算,如 ptr + 1,这同样适用于数组名。

3. 数组与指针的主要区别

现在让我们来看看数组和指针之间的一些关键区别:

3.1 数组名是常量

数组名始终指向数组的起始位置,不能被重新赋值为指向其他位置的地址。

1#include <stdio.h>
2
3int main() {
4    int arr[5] = {1, 2, 3, 4, 5};
5    int *ptr = arr; // arr 被视为指向第一个元素的指针
6
7    printf("Value at arr: %d\n", *arr); // 输出 1
8    printf("Value at ptr: %d\n", *ptr); // 输出 1
9
10    // 下面的代码会导致编译错误
11    // arr = ptr; // 错误:数组名不能被重新赋值
12
13    return 0;
14}

输出:

Value at arr: 1
Value at ptr: 1

解释

  • int *ptr = arr; 将 arr 视为指向第一个元素的指针。
  • arr = ptr; 导致编译错误,因为数组名不能被重新赋值。

3.2 数组名与指针的类型不同

数组名的类型与指针的类型不同,这在函数参数传递时尤为明显。

1#include <stdio.h>
2
3void printArray(int arr[], int size) {
4    for (int i = 0; i < size; i++) {
5        printf("%d ", arr[i]);
6    }
7    printf("\n");
8}
9
10int main() {
11    int arr[5] = {1, 2, 3, 4, 5};
12
13    printArray(arr, 5); // arr 被传递给函数
14
15    return 0;
16}

输出:

1 2 3 4 5

解释

  • void printArray(int arr[], int size) 接受一个数组作为参数。
  • printArray(arr, 5); 传递数组给函数。

3.3 数组作为函数参数时的退化

当数组作为函数参数时,它会退化为指针,这意味着传递给函数的是数组首元素的地址,而不是整个数组。

1#include <stdio.h>
2
3void printArray(int arr[], int size) {
4    // arr 在这里被视为指针
5    printf("Address of arr in function: %p\n", (void *)arr);
6}
7
8int main() {
9    int arr[5] = {1, 2, 3, 4, 5};
10
11    printf("Address of arr in main: %p\n", (void *)&arr);
12    printArray(arr, 5); // arr 作为指针传递给函数
13
14    return 0;
15}

输出:

1Address of arr in main: 0x7fff5fbff3e0
2Address of arr in function: 0x7fff5fbff3e0

解释

  • printArray(arr, 5); 传递数组给函数。
  • arr 在函数中被视为指向数组第一个元素的指针。

3.4 数组大小的信息丢失

当数组作为函数参数时,编译器不知道数组的实际大小。这可能导致潜在的问题,如越界访问。

1#include <stdio.h>
2
3void printArray(int arr[], int size) {
4    for (int i = 0; i < size; i++) {
5        printf("%d ", arr[i]);
6    }
7    printf("\n");
8}
9
10int main() {
11    int arr[5] = {1, 2, 3, 4, 5};
12
13    printArray(arr, 5); // 正确
14    printArray(arr, 10); // 可能导致越界访问
15
16    return 0;
17}

输出:

11 2 3 4 5

解释

  • printArray(arr, 10); 可能导致越界访问。

4. 数组与指针的高级用法

数组和指针在高级编程中有着广泛的应用,例如多维数组、指针数组等。

4.1 多维数组与指针

多维数组可以被视为指针数组。

1#include <stdio.h>
2
3void printMatrix(int (*matrix)[3], int rows) {
4    for (int i = 0; i < rows; i++) {
5        for (int j = 0; j < 3; j++) {
6            printf("%d ", matrix[i][j]);
7        }
8        printf("\n");
9    }
10}
11
12int main() {
13    int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
14
15    printMatrix(matrix, 2); // 传递多维数组给函数
16
17    return 0;
18}

输出:

1 2 3 
4 5 6 

解释

  • void printMatrix(int (*matrix)[3], int rows) 接受一个指针数组作为参数。
  • printMatrix(matrix, 2); 传递多维数组给函数。

结论

数组和指针在C语言中有着密切的关系,但它们之间也存在着明显的区别。理解这些差异对于编写正确和高效的代码至关重要。通过上述示例,你应该已经了解了数组和指针之间的主要区别。这种能力对于处理复杂的数据结构和编写更高效的程序非常有帮助。

 

相关文章:

C语言中的数组并非指针:深入理解数组和指针的区别

前言 在C语言中&#xff0c;数组和指针是两个非常重要的概念&#xff0c;它们在很多方面有着紧密的联系&#xff0c;但也存在显著的区别。尽管数组名有时可以像指针那样使用&#xff0c;但它们本质上并不是一回事。理解这些差异对于编写正确和高效的代码至关重要。本文将深入探…...

Topaz Video AI for Mac 视频无损放大软件安装教程【保姆级,操作简单轻松上手】

Mac分享吧 文章目录 Topaz Video AI for Mac 视频无损放大软件 安装完成&#xff0c;软件打开效果一、Topaz Video AI 视频无损放大软件 Mac电脑版——v5.3.5⚠️注意事项&#xff1a;1️⃣&#xff1a;下载软件2️⃣&#xff1a;安装软件&#xff0c;将安装包从左侧拖入右侧文…...

虚函数和纯虚函数是 C++ 中实现多态性的关键概念

虚函数&#xff08;Virtual Function&#xff09; 定义&#xff1a;虚函数是在基类中使用 virtual 关键字声明的函数&#xff0c;目的是允许派生类重写该函数。用途&#xff1a;通过虚函数&#xff0c;基类指针或引用可以调用派生类中重写的函数&#xff0c;从而实现动态多态性…...

计算机网络IP地址分类,子网掩码,子网划分复习资料

IP 地址的概念 IP 地址是独立于硬件地址的逻辑地址&#xff0c;它是由软件提供的地址。 IP 地址是网络层地址。 IP 编址方案和分类 IP 地址由 32 位二进制数构成&#xff0c;分为前缀(网络地址)和后缀(主机地址) 同一网段中每台计算机的 IP 地址是唯一的网络地址的分配全球…...

LINUX下使用SQLite查看.db数据库文件

目录 1. 安装 SQLite 对于 Debian/Ubuntu 系统&#xff1a; 2.安装完成后操作 打开 SQLite 命令行工具并连接到数据库文件 查看表结构 查询表中的数据 执行其他 SQL 操作 3. 退出 SQLite 命令行工具 4. 使用图形化工具&#xff08;可选&#xff09; 总结 在 Linux 环…...

基于uniapp微信小程序的校园二手书交易系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…...

性能测试中的操作系统参数优化

目录 以下是一些针对性能测试的操作系统优化建议 关闭不必要的服务和程序&#xff1a; 更新系统和驱动程序&#xff1a; 优化电源管理设置&#xff1a; 调整内存配置&#xff1a; 网络配置优化&#xff1a; 磁盘I/O优化&#xff1a; 内核参数调整&#xff1a; 安全软件…...

rabbitmq高级特性(2)TTL、死信/延迟队列、事务与消息分发

目录 1.TTL 1.1.设置消息过期时间 1.2.设置队列过期时间 2.死信队列 2.1.介绍 2.2.演示 3.延迟队列 3.1.模拟实现延迟队列 3.2.延迟队列插件 4.事务与消息分发 4.1.事务 4.2.消息分发 1.TTL 所谓的ttl&#xff0c;就是过期时间。对于rabbitmq&#xff0c;可以设置…...

了解一下,RN中怎么加载 threejs的

在React Native&#xff08;RN&#xff09;中加载和使用Three.js&#xff0c;一个流行的3D图形库&#xff0c;通常需要一些额外的步骤&#xff0c;因为Three.js主要是为Web浏览器设计的&#xff0c;而React Native则使用原生的渲染引擎。不过&#xff0c;有一些方法可以在React…...

笔记整理—linux驱动开发部分(1)驱动梗概

驱动可以分为广义上的和狭义上的驱动。广义上的驱动是用于操作硬件的代码&#xff0c;而狭义上的驱动为基于内核系统之上让硬件去被操作的逻辑方法。 linux体系架构&#xff1a; 1.分层思想 &#xff1a;在OS中间还会有许多层。 : 2.驱动的上面是系统调用&#xff08;API&…...

金融领域中的敏感性分析和期权价值计算相关的操作

代码主要进行了金融领域中的敏感性分析和期权价值计算相关的操作。首先通过一系列方程求解S3和S2的值,然后基于这些值以及给定的参数计算一些中间变量(a1、a2、a3、b1、b2、b3),最后利用多元正态分布函数(mvncdf)和一元正态分布函数(normcdf)计算期权价值C、净现值(NP…...

GraphQL系列 - 第1讲 GraphQL语法入门

目录 一、介绍GraphQL二、GraphQL基本使用方法三、Schema 定义语言 (SDL)3.1 类型定义1&#xff09;对象类型2&#xff09;标量类型3&#xff09;枚举类型4&#xff09;输入类型5&#xff09;列表类型6&#xff09;非空类型7&#xff09;接口类型8&#xff09;联合类型 3.2 查询…...

015:地理信息系统开发平台ArcGIS Engine10.2与ArcGIS SDK for the Microsoft .NET Framework安装教程

摘要&#xff1a;本文详细介绍地理信息系统开发平台ArcGIS Engine10.2与ArcGIS SDK for the Microsoft .NET Framework的安装流程。 一、软件介绍 ArcGIS Engine 10.2是由Esri公司开发的一款强大的GIS&#xff08;地理信息系统&#xff09;开发平台。该软件基于ArcGIS 10.2 fo…...

Android——显式/隐式Intent

概述 在Android中&#xff0c;Intent是各个组件之间信息通信的桥梁&#xff0c;它用于Android各组件的通信。 Intent 的组成部分 一、显式 Intent 第一种方式 Intent intent new Intent(this, ActFinishActivity.class);startActivity(intent);第二种方式 Intent intent …...

【鸿蒙HarmonyOS实战:通过华为应用市场上架测试版App实现HBuilder X打包的UniApp项目的app转hap教程(邀请码)方式教程详解】

鸿蒙HarmonyOS实战&#xff1a;通过华为应用市场上架测试版App实现HBuilder X打包的UniApp项目的app转hap教程&#xff08;邀请码&#xff09;方式详解 在使用uniapp打包的鸿蒙项目的过程中&#xff0c;由于生成的是app文件&#xff0c;而hdc传给鸿蒙HarmonyOS系统需要的是hap文…...

一篇文章入门傅里叶变换

文章目录 傅里叶变换欧拉公式傅里叶变换绕圈记录法质心记录法傅里叶变换公式第一步&#xff1a;旋转的表示第二步&#xff1a;缠绕的表示第三步&#xff1a;质心的表示最终步&#xff1a;整理积分限和系数 参考文献 傅里叶变换 在学习傅里叶变换之前&#xff0c;我们先来了解一…...

基于python的语音识别与蓝牙通信的温控系统

基于python的语音识别与蓝牙通信的温控系统毕设项目 大家好&#xff0c;我是陈辰学长&#xff0c;一名在 Java 圈辛勤劳作的码农。今日&#xff0c;要和大家分享的是一款基于python的语音识别与蓝牙通信的温控系统毕设项目。项目源码以及部署相关事宜&#xff0c;请联系陈辰学…...

Pandas Series学习

1.Series简介 Pandas Series类似表格的列&#xff08;column&#xff09;&#xff0c;类似于一维数组&#xff0c;可以保存任何数据类型&#xff0c;具有标签&#xff08;索引&#xff09;&#xff0c;使得数据在处理分析时更具灵活性。Series数据结构是非常有用的&#xff0c;…...

为什么要探索太空?这对我们有什么好处?

几个世纪以来&#xff0c;人类一直着迷于宇宙的奥秘&#xff0c;这驱使我们冒险离开地球&#xff0c;去探索太阳系之外的未知环境。在当今世界&#xff0c;我们为什么要进行太空探索之旅这个问题&#xff0c;远不止出于单纯的好奇。 归根结底&#xff0c;太空探索是一种必要之…...

uniapp开发【选择地址-省市区功能】,直接套用即可

一、效果展示 二、代码 <template><view><view class="user_info"><view class="item"...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...