C语言中数组与指针的异同(详解区别)

数组与指针

1. 两者在什么情况下是不同的

声明与定义时,两者并不等价

下面代码无法运行,其本质原因就是定义与声明时,两者并不等价,若要引用外部数组,就必须声明为数组

//文件1
int mango[100];
//文件2
extern int *mango; //❌报错,编译失败

要明白上面的程序为什么失败,首先要懂得程序执行的细节,首先用变量与指针举例:
图1-变量与指针访问数据
  如图1所示,程序通过a读取内存的值时,只要去a的地址,直接取值就能获取到数据,但是通过*b读取到同样位置的值,首先要去b的地址拿b的值(也就是a的地址),解引用的过程就是去a的地址并获取到地址上存储的值,其中 通过b获取内存中的地址值、通过a获取内存中的数值 这两个过程是一样的,都是通过变量拿到内存中的值,但是通过解引用拿到目标数据的过程,是指针方式独有的、相比于变量取值多出来的操作。

现在将问题换成数组与指针,首先分析正常用指针访问数组的过程:
图2-数组与指针访问数据
如图2所示
①通过数组名[下标]的方式访问数组时,只要两步:从数组名a拿到起始地址 → 计算(arr+偏移)目标地址并取值
②通过指针访(或指针[下标])访问数组的过程需要三步:从指针名拿到指针变量b的地址 → 拿到此地址存储的值(数组起始地址) → 计算(起始地址+偏移)得到目标地址并取值

??? 表示未知的内存区域存储的数据

理清上述过程,便可以分析最初的代码失败的原因:

文件1中:定义 int mongo[10];
文件2中:声明 extern int *mongo;

由于文件2中声明的 mongo 与文件1中定义的mongo是有本质区别的,所以编译会失败,下面图示是在假设编译通过后,在文件2中使用mongo指针访问数组时的情形;
在这里插入图片描述
  根据图3 ,由于声明并不会创建新的变量,它所表达的意思是此处声明的mongo就是文件1中定义的mongo,因为文件2中以声明指针的方式表示要用文件1声明的mongo数组。所以如果编译通过,那么就会把文件2中的mongo作为数组名,取mongo[1]的值时将以数组的方式完成读取过程(因为声明的意思就是我要用已有的别处定义好的变量),于是,按照数组访问的流程:首先将mongo的地址(&mongo)当作起始地址,把 (&mongo+偏移) 作为目标数据的地址,然后取了 [mongo+偏移] 地址上对应的值,这显然是错误的,所以上述过程根本不会出现,因为两者根本就是两个东西,编译不通过(理由:在这种情况下,指针与数组是不等价的)

如果,在文件2中声明 extern int mongo[];,这样是可以的,因为这里的mongo和文件1的mongo类型是一样的,用这个mongo访问数组的过程与文件1中的mongo也是一致的。

两者本身的地址并不相同

int mango[100];
int *raisin;

mango数组的定义分配了100个int的空间。
  而指针的定义则申请一个地址容纳该指针。指针的名字是raisin,它可以指向任何一个int变量(或int型数组)。指针变量raisin本身始终位于同一个地址,但它的内容可以随意变化,可以指向不同地址的int变量。这些不同的int变量可以有不同的值。mango数组的地址并不能改变,在不同的时候它的内容可以不同,但它总是表示100个连续的内存空间。

区别汇总

指针数组
保存数据的地址保存数据
间接访问数据,首先取得指针的内容,把它作
为地址,然后从这个地址提取数据。
如果指针有一个下标[I],就把指针的内容加
上 I 作为地址,从中提取数据
直接访问数据,a[I]只是简单地以a+I为地址取得数据
通常用于动态数据结构通常用于存储固定数目且数据类型相同的元素
相关的函数为malloc(), free()隐式分配和回收
通常指向匿名数据(用malloc分配的就是)自身即为数据名

2. 数组和指针等价的情形

注:同时汇总了不等价的情况以增强对比

  • 数组

    • 声明与定义

      • 🔴声明 extern char a[];不能改写成指针形式
      • 🔴定义 char a[10];不能改写成指针形式
      • 🟢函数参数 func(char a[]);指针/数组形式都可以
    • 在表达式中

      • 🟢c=a[i];可以改写成指针形式(你不改编译器也会改)

🔴另外,下面三种情况中,对数组的引用不能用指向数组首个元素的指针代替

  • 数组作为sizeof()的操作数一显然此时需要的是整个数组的大小,而不是指针所指向的第一个元素的大小
  • 使用&操作符取数组的地址。(对数组名操作才能拿到“数组地址(带有数组长度信息”)
  • 数组是一个字符串(或宽字符串)常量初始值。

本文是笔者对《C专家编程》第四章内容的个人理解与总结,欢迎指出其中的错误与不足!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值