数组在很多情况下是和指针等价的,数组的下标运算和指针的解引用也有等价形式:arr[i] == *(arr + 1);但是也有一些情况下数组和指针是不一样的:extern int arr[]; extern int *arr;

这里持续记录一下指针和数组的异同(以下来自于C专家编程)

首先明确一下几个定义:

  • 声明和定义:C语言中的对象必须有且只有一个定义,但是可以有多个extern声明。
定义 只能出现在一个地方 确定对象的类型并分配内存,用于创建新的对象。例如:int my_array[100]
声明 可以多次出现 描述对象的类型,用于指代其他地方定义的对象(例如在其他文件里)例如:extern int my_array[]
    • 区分定义和声明:

      • 声明相当于普通的声明:它所说明的并非自身,而是描述其他地方的创建的对象
      • 定义相当于特殊的声明:它为对象分配内存
  • 左值和右值(地址和地址的内容):

注:C语言引入了"可修改的左值"这个术语,可修改的左值指的是可以放在赋值语句左边。这个术语是为了与数组名区分,数组名也用于确定对象在内存中的位置,也是左值,但它不能作为赋值的对象。因此,数组名是个左值但不是可修改的左值。

  1. 指针与数组的不同:
    • 编译器为每个变量分配一个地址(左值),这个地址在编译时可知,而且该变量在运行时一直保存于这个地址。相反,存储于变量中的值(它的右值)只有在运行时才可知。如果需要用到变量中存储的值,编译器就要发出指令从指定地址读入变量值并将它存于寄存器中。所以,如果编译器需要一个地址来执行某种操作,它就可以直接进行操作(因为符号的地址在编译时可知),并不需要增加指令首先取得具体的地址。相反,对于指针,必须首先在运行时取得它的当前值(取得指针本身所存的右值),然后才能对它进行解除引用操作。
    • 故:int a[100] 和 extern int a[]都表明a是一个数组,也就是一个内存地址,数组内的字符可以从这个地址找到。从数组提取一个字符,只要简单的从符号表显示的a的地址加上下标,需要的字符就位于这个地址中。相反,如果声明extern int *p,它告诉编译器p是一个指针,它指向的对象时一个字符。为了取得这个字符,必须得到地址p的内容(注意数组a本身就是一个地址),把它作为字符的地址并从这个地址中取得这个字符,相比数组a来说多了一次额外的提取。取a中的字符和p所指的字符见下图:

    • 由上可知,int a[100] 告诉编译器a是一个数组,本身就是一个地址。int *p告诉编译器p是一个指针,p所在的地址中存的是一个int的地址。

下面继续对数组和指针进行解释:"当定义为指针,但以数组方式引用"时会发生什么

    • 这时编译器所执行的是对内存进行间接引用。之所以会如此是因为我们告诉编译器我们拥有的是一个指针。

对照上图的访问方式:
                    char *p = "abcdefg";    ...... p[3]
                    和
                    char a[] = "abcdefg";    ...... a[3]
                    这两种情况都可以取得字符'd',但两者的途径却很不一样。

当写了extern char *p的时候,编译器将会:
                     a.取得符号表中p的地址,提取存储于此处的指针
                     b.把下标所表示的偏移量与指针的值相加,产生一个地址
                     c.访问上面这个地址,取得字符。

    • 考虑如果p被声明为extern char *p;但是它原先的定义却是char p[10];这种情形。当用p[i]这种形式提取这个声明的内容的时候,实际上得到的是一个字符。但是按照上面的方法,编译器确把它当成是一个指针,就会先去取这个地址中所存的地址,但是其实p的地址中现在存的其实已经是一个int型了,吧ASCII字符解释为地址显然是驴唇不对马嘴。相反的,如果p被声明为extern char p[];但是它原先定义却是int *p;这种情形的话,那么p[i],编译器会直接取地址(p + i),显然这也是不对的,因为此时直接把p的地址和i相加其实是一个不存在的地址。
    • 可见数组和指针在这种情况下是不同的。在C语言中,对数组的引用其实引用的是地址本身(不可变左值),但是对指针的引用其实是引用指针所在地址中的内容(右值)。

数组和指针的其他区别

指针 数组
保存数据的地址 保存数据

间接访问数据,首先取得指针的内容,把它作为地址,然后从这个地址提取数据。

如果指针有一个下标[I],就把指针的内容加上I作为地址,从中提取数组

直接访问数据,a[I]只是简单的一a + I为地址取得数据
通常用于动态数据结构 通常用于存储固定数目且数据类型相同的元素
相关的函数为malloc(),free() 隐式分配和删除
通常指向匿名数据 自身即为数据名

2.数组和指针的相同点:


除了上面的几种不同的情况以外,很多情况下数组和指针是可以等同看待的,例如在作为函数的形参的时候,数组和指针是等价的:void foo(int *); == void foo(int[]);

很多情况下我们使用数组和指针的时候也是非常类似的,例如 arr[n] == *(arr + n)

C中 数组和指针的异同的更多相关文章

  1. C语言中数组与指针的异同之处!你不知道的编程奥秘~

    C语言的数组和指针一直是两个容易混淆的东西,当初在学习的时候,也许为了通过考试会对指针和数组的一些考点进行突击,但是很多极其细节的东西也许并不是那么清楚.本篇侧重点在于分析数组与指针的关系,什么时候数 ...

  2. C/C++中数组与指针的关系探究

    数组与指针 长期以来,在C/C++中,数组名和指向数组首元素的指针常量到底是以一种什么关系,一直困扰着很多人.很多地方,甚至是一些教科书中都在说,"数组名就是一个指向数组首元素的指针常量&q ...

  3. 《挑战30天C++入门极限》新手入门:C/C++中数组和指针类型的关系

        新手入门:C/C++中数组和指针类型的关系 对于数组和多维数组的内容这里就不再讨论了,前面的教程有过说明,这里主要讲述的数组和指针类型的关系,通过对他们之间关系的了解可以更加深入的掌握数组和指 ...

  4. 由strcat函数引发的C语言中数组和指针问题的思考

    问题一 首先,来看一下下面这段代码: #include <stdio.h> #include <string.h> int main() { char *str = " ...

  5. c语言中数组,指针数组,数组指针,二维数组指针

    1.数组和指针 ] = {,,,,};// 定义数组 // 1. 指针和数组的关系 int * pa = array; pa = array; // p[0] == *(p+0) == array[0 ...

  6. C中数组与指针【转】

    在这里随便定义一个数组 int arr[5]; arr现在就是数组名, arr 代表的是该数组整块内存,即sizeof(arr) == 20 (假设sizeof(int) == 4), arr 里的内 ...

  7. C 中数组和指针的区别

    联系: 1,一个通过数组和下标实现的表达式可等价地通过指针和偏移量实现. 2,当数组名传递给一个函数时,实际上传递的是该数组第一个元素的地址. 区别: 1,指针是一个变量,因此,在C语言中,语句pa= ...

  8. php中数组的指针

    利用PHP内置的函数 key() 获得键. current()获得值, next(); prev();移动到上一个 reset();//重置,移动到第一个元素 end();//移动到最后一个元素上 注 ...

  9. 深入理解C/C++数组和指针

    C语言中数组和指针是一种很特别的关系,首先本质上肯定是不同的,本文从各个角度论述数组和指针. 一.数组与指针的关系数组和指针是两种不同的类型,数组具有确定数量的元素,而指针只是一个标量值.数组可以在某 ...

随机推荐

  1. linux下查找字符串的命令

    1. set命令可以显示出当前shell下所有全局参量定义及其值;   2. 查找并删除当前目录下小文件: find . -type f -size -10k -exec rm {} \; 说明: w ...

  2. eclipse如何导出WAR包

    WAR包是用于将java项目部署在中间件上的,例如部署在Tomcat,Weblogic,WebSphere等等,那么如何使用eclipse导出WAR包呢? 工具/原料 eclipse 方法/步骤   ...

  3. HTML5页面直接调用百度地图API,获取当前位置,直接导航目的地

    <!DOCTYPE html> <html lang="zh-cmn-Hans"> <meta charset="UTF-8"&g ...

  4. 专题训练——[kuangbin带你飞]最短路练习

    最短路练习 0. Til the Cows Come Home  POJ - 2387 完美的模板题 //#include<Windows.h> #include<iostream& ...

  5. 洛谷——P1731 [NOI1999]生日蛋糕

    P1731 [NOI1999]生日蛋糕 搜索+剪枝 常见的剪枝: 若当前状态+后面所要搜索的最差的状态$>$或是$<$最后的状态,就返回 预处理最差的状态 #include<iost ...

  6. [HEOI2013]ALO

    题目描述: 现在你拥有 n 颗宝石,每颗宝石有一个能量密度,记为 ai,这些宝石的能量 密度两两不同.现在你可以选取连续的一些宝石(必须多于一个)进行融合,设 为 ai, ai+1, …, aj,则融 ...

  7. 关于C/C++的一些思考(2)

    C++引入类机制的目的: 从语法上将数据和操作捆绑在一起: 从语法上消除变量和函数的名字冲突: 从语法上允许服务端设计者控制数据和函数的访问权限: 从工程上支持数据封装.信息隐藏.将责任推向服务端.减 ...

  8. 零基础入门学习Python(18)--函数:灵活即强大

    前言 上一节课我们基本介绍Python函数的用法,这一节课我们主要针对函数的参数进行进一步的深入学习. 知识点 形参(parameter)和实参(argument) >>> def ...

  9. yum 软件管理器

    yum软件管理器 yum是一个强大的软件包管理器,能够自动解决安装时rpm包之间的依赖关系. 一.使用yum管理软件包 1.使用命令 yum help 查看使用方法 [root@majinhai ~] ...

  10. cadence中画焊盘注意事项

    贴片焊盘的层面剖析图如下: 其中Paste Mask Top层用于制作钢网,可以做成与Top层相同的大小.阻焊层一般比顶层大0.1mm(方形焊盘的长,宽,圆形焊盘的直径). 助焊层与阻焊层区别 两个层 ...